feat: 完整重构小程序匹配功能 + 修复UI对齐 + 文章数据API
主要更新: 1. 按H5网页端完全重构匹配功能(match页面) - 4种匹配类型: 创业合伙/资源对接/导师顾问/团队招募 - 资源对接等类型弹出手机号/微信号输入框 - 去掉重新匹配按钮,改为返回按钮 2. 修复所有卡片对齐和宽度问题 - 目录页附录卡片居中 - 首页阅读进度卡片满宽度 - 我的页面菜单卡片对齐 - 推广中心分享卡片统一宽度 3. 修复目录页图标和文字对齐 - section-icon固定40rpx宽高 - section-title与图标垂直居中 4. 更新真实完整文章标题(62篇) - 从book目录读取真实markdown文件名 - 替换之前的简化标题 5. 新增文章数据API - /api/db/chapters - 获取完整书籍结构 - 支持按ID获取单篇文章内容
This commit is contained in:
194
app/api/db/book/route.ts
Normal file
194
app/api/db/book/route.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
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 })
|
||||
}
|
||||
}
|
||||
272
app/api/db/chapters/route.ts
Normal file
272
app/api/db/chapters/route.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* Soul创业实验 - 文章数据API
|
||||
* 用于存储和获取章节数据
|
||||
*/
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
// 文章数据结构
|
||||
interface Section {
|
||||
id: string
|
||||
title: string
|
||||
isFree: boolean
|
||||
price: number
|
||||
content?: string
|
||||
filePath?: string
|
||||
}
|
||||
|
||||
interface Chapter {
|
||||
id: string
|
||||
title: string
|
||||
sections: Section[]
|
||||
}
|
||||
|
||||
interface Part {
|
||||
id: string
|
||||
number: string
|
||||
title: string
|
||||
subtitle: string
|
||||
chapters: Chapter[]
|
||||
}
|
||||
|
||||
// 书籍目录结构映射
|
||||
const BOOK_STRUCTURE = [
|
||||
{
|
||||
id: 'part-1',
|
||||
number: '一',
|
||||
title: '真实的人',
|
||||
subtitle: '人与人之间的底层逻辑',
|
||||
folder: '第一篇|真实的人',
|
||||
chapters: [
|
||||
{ id: 'chapter-1', title: '第1章|人与人之间的底层逻辑', folder: '第1章|人与人之间的底层逻辑' },
|
||||
{ id: 'chapter-2', title: '第2章|人性困境案例', folder: '第2章|人性困境案例' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-2',
|
||||
number: '二',
|
||||
title: '真实的行业',
|
||||
subtitle: '电商、内容、传统行业解析',
|
||||
folder: '第二篇|真实的行业',
|
||||
chapters: [
|
||||
{ id: 'chapter-3', title: '第3章|电商篇', folder: '第3章|电商篇' },
|
||||
{ id: 'chapter-4', title: '第4章|内容商业篇', folder: '第4章|内容商业篇' },
|
||||
{ id: 'chapter-5', title: '第5章|传统行业篇', folder: '第5章|传统行业篇' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-3',
|
||||
number: '三',
|
||||
title: '真实的错误',
|
||||
subtitle: '我和别人犯过的错',
|
||||
folder: '第三篇|真实的错误',
|
||||
chapters: [
|
||||
{ id: 'chapter-6', title: '第6章|我人生错过的4件大钱', folder: '第6章|我人生错过的4件大钱' },
|
||||
{ id: 'chapter-7', title: '第7章|别人犯的错误', folder: '第7章|别人犯的错误' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-4',
|
||||
number: '四',
|
||||
title: '真实的赚钱',
|
||||
subtitle: '底层结构与真实案例',
|
||||
folder: '第四篇|真实的赚钱',
|
||||
chapters: [
|
||||
{ id: 'chapter-8', title: '第8章|底层结构', folder: '第8章|底层结构' },
|
||||
{ id: 'chapter-9', title: '第9章|我在Soul上亲访的赚钱案例', folder: '第9章|我在Soul上亲访的赚钱案例' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-5',
|
||||
number: '五',
|
||||
title: '真实的社会',
|
||||
subtitle: '未来职业与商业生态',
|
||||
folder: '第五篇|真实的社会',
|
||||
chapters: [
|
||||
{ id: 'chapter-10', title: '第10章|未来职业的变化趋势', folder: '第10章|未来职业的变化趋势' },
|
||||
{ id: 'chapter-11', title: '第11章|中国社会商业生态的未来', folder: '第11章|中国社会商业生态的未来' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 免费章节ID
|
||||
const FREE_SECTIONS = ['1.1', 'preface', 'epilogue', 'appendix-1', 'appendix-2', 'appendix-3']
|
||||
|
||||
// 从book目录读取真实文章数据
|
||||
function loadBookData(): Part[] {
|
||||
const bookPath = path.join(process.cwd(), 'book')
|
||||
const parts: Part[] = []
|
||||
|
||||
for (const partConfig of BOOK_STRUCTURE) {
|
||||
const part: Part = {
|
||||
id: partConfig.id,
|
||||
number: partConfig.number,
|
||||
title: partConfig.title,
|
||||
subtitle: partConfig.subtitle,
|
||||
chapters: []
|
||||
}
|
||||
|
||||
for (const chapterConfig of partConfig.chapters) {
|
||||
const chapter: Chapter = {
|
||||
id: chapterConfig.id,
|
||||
title: chapterConfig.title,
|
||||
sections: []
|
||||
}
|
||||
|
||||
const chapterPath = path.join(bookPath, partConfig.folder, chapterConfig.folder)
|
||||
|
||||
try {
|
||||
const files = fs.readdirSync(chapterPath)
|
||||
const mdFiles = files.filter(f => f.endsWith('.md')).sort()
|
||||
|
||||
for (const file of mdFiles) {
|
||||
// 从文件名提取ID和标题
|
||||
const match = file.match(/^(\d+\.\d+)\s+(.+)\.md$/)
|
||||
if (match) {
|
||||
const [, id, title] = match
|
||||
const filePath = path.join(chapterPath, file)
|
||||
|
||||
chapter.sections.push({
|
||||
id,
|
||||
title: title.replace(/[::]/g, ':'), // 统一冒号格式
|
||||
isFree: FREE_SECTIONS.includes(id),
|
||||
price: 1,
|
||||
filePath
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 按ID数字排序
|
||||
chapter.sections.sort((a, b) => {
|
||||
const [aMajor, aMinor] = a.id.split('.').map(Number)
|
||||
const [bMajor, bMinor] = b.id.split('.').map(Number)
|
||||
return aMajor !== bMajor ? aMajor - bMajor : aMinor - bMinor
|
||||
})
|
||||
|
||||
} catch (e) {
|
||||
console.error(`读取章节目录失败: ${chapterPath}`, e)
|
||||
}
|
||||
|
||||
part.chapters.push(chapter)
|
||||
}
|
||||
|
||||
parts.push(part)
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
// 读取文章内容
|
||||
function getArticleContent(sectionId: string): string | null {
|
||||
const bookData = loadBookData()
|
||||
|
||||
for (const part of bookData) {
|
||||
for (const chapter of part.chapters) {
|
||||
const section = chapter.sections.find(s => s.id === sectionId)
|
||||
if (section?.filePath) {
|
||||
try {
|
||||
return fs.readFileSync(section.filePath, 'utf-8')
|
||||
} catch (e) {
|
||||
console.error(`读取文章内容失败: ${section.filePath}`, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// GET - 获取所有章节数据
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const sectionId = searchParams.get('id')
|
||||
const includeContent = searchParams.get('content') === 'true'
|
||||
|
||||
try {
|
||||
// 如果指定了章节ID,返回单篇文章内容
|
||||
if (sectionId) {
|
||||
const content = getArticleContent(sectionId)
|
||||
if (content) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: { id: sectionId, content }
|
||||
})
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '文章不存在'
|
||||
}, { status: 404 })
|
||||
}
|
||||
}
|
||||
|
||||
// 返回完整书籍结构
|
||||
const bookData = loadBookData()
|
||||
|
||||
// 统计总章节数
|
||||
let totalSections = 0
|
||||
for (const part of bookData) {
|
||||
for (const chapter of part.chapters) {
|
||||
totalSections += chapter.sections.length
|
||||
}
|
||||
}
|
||||
// 加上序言、尾声和3个附录
|
||||
totalSections += 5
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
totalSections,
|
||||
parts: bookData,
|
||||
appendix: [
|
||||
{ id: 'appendix-1', title: '附录1|Soul派对房精选对话', isFree: true },
|
||||
{ id: 'appendix-2', title: '附录2|创业者自检清单', isFree: true },
|
||||
{ id: 'appendix-3', title: '附录3|本书提到的工具和资源', isFree: true }
|
||||
],
|
||||
preface: { id: 'preface', title: '序言|为什么我每天早上6点在Soul开播?', isFree: true },
|
||||
epilogue: { id: 'epilogue', title: '尾声|这本书的真实目的', isFree: true }
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取章节数据失败:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '获取数据失败'
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// POST - 同步章节数据到数据库(预留接口)
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const bookData = loadBookData()
|
||||
|
||||
// 这里可以添加数据库写入逻辑
|
||||
// 目前先返回成功,数据已从文件系统读取
|
||||
|
||||
let totalSections = 0
|
||||
for (const part of bookData) {
|
||||
for (const chapter of part.chapters) {
|
||||
totalSections += chapter.sections.length
|
||||
}
|
||||
}
|
||||
totalSections += 5 // 序言、尾声、3个附录
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: '章节数据同步成功',
|
||||
data: {
|
||||
totalSections,
|
||||
partsCount: bookData.length,
|
||||
chaptersCount: bookData.reduce((acc, p) => acc + p.chapters.length, 0)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('同步章节数据失败:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '同步数据失败'
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
96
app/api/db/distribution/route.ts
Normal file
96
app/api/db/distribution/route.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { distributionDB, purchaseDB } from '@/lib/db'
|
||||
|
||||
// 获取分销数据
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const type = searchParams.get('type')
|
||||
const referrerId = searchParams.get('referrer_id')
|
||||
|
||||
// 获取佣金记录
|
||||
if (type === 'commissions') {
|
||||
const commissions = await distributionDB.getAllCommissions()
|
||||
return NextResponse.json({ success: true, commissions })
|
||||
}
|
||||
|
||||
// 获取指定推荐人的绑定
|
||||
if (referrerId) {
|
||||
const bindings = await distributionDB.getBindingsByReferrer(referrerId)
|
||||
return NextResponse.json({ success: true, bindings })
|
||||
}
|
||||
|
||||
// 获取所有绑定关系
|
||||
const bindings = await distributionDB.getAllBindings()
|
||||
return NextResponse.json({ success: true, bindings })
|
||||
} catch (error: any) {
|
||||
console.error('Get distribution data 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 { type, data } = body
|
||||
|
||||
if (type === 'binding') {
|
||||
const binding = await distributionDB.createBinding({
|
||||
id: `binding_${Date.now()}`,
|
||||
...data,
|
||||
bound_at: new Date().toISOString(),
|
||||
expires_at: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // 30天有效期
|
||||
status: 'active'
|
||||
})
|
||||
return NextResponse.json({ success: true, binding })
|
||||
}
|
||||
|
||||
if (type === 'commission') {
|
||||
const commission = await distributionDB.createCommission({
|
||||
id: `commission_${Date.now()}`,
|
||||
...data,
|
||||
status: 'pending'
|
||||
})
|
||||
return NextResponse.json({ success: true, commission })
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '未知操作类型'
|
||||
}, { status: 400 })
|
||||
} catch (error: any) {
|
||||
console.error('Create distribution record 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, status } = body
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '缺少记录ID'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
await distributionDB.updateBindingStatus(id, status)
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error: any) {
|
||||
console.error('Update distribution status error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
16
app/api/db/init/route.ts
Normal file
16
app/api/db/init/route.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { initDatabase } from '@/lib/db'
|
||||
|
||||
// 初始化数据库表
|
||||
export async function POST() {
|
||||
try {
|
||||
await initDatabase()
|
||||
return NextResponse.json({ success: true, message: '数据库初始化成功' })
|
||||
} catch (error: any) {
|
||||
console.error('Database init error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message || '数据库初始化失败'
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
106
app/api/db/purchases/route.ts
Normal file
106
app/api/db/purchases/route.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { purchaseDB, userDB, distributionDB } from '@/lib/db'
|
||||
|
||||
// 获取购买记录
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const userId = searchParams.get('user_id')
|
||||
|
||||
if (userId) {
|
||||
const purchases = await purchaseDB.getByUserId(userId)
|
||||
return NextResponse.json({ success: true, purchases })
|
||||
}
|
||||
|
||||
const purchases = await purchaseDB.getAll()
|
||||
return NextResponse.json({ success: true, purchases })
|
||||
} catch (error: any) {
|
||||
console.error('Get purchases 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 {
|
||||
user_id,
|
||||
type,
|
||||
section_id,
|
||||
section_title,
|
||||
amount,
|
||||
payment_method,
|
||||
referral_code
|
||||
} = body
|
||||
|
||||
// 创建购买记录
|
||||
const purchase = await purchaseDB.create({
|
||||
id: `purchase_${Date.now()}`,
|
||||
user_id,
|
||||
type,
|
||||
section_id,
|
||||
section_title,
|
||||
amount,
|
||||
payment_method,
|
||||
referral_code,
|
||||
referrer_earnings: 0,
|
||||
status: 'completed'
|
||||
})
|
||||
|
||||
// 更新用户购买状态
|
||||
if (type === 'fullbook') {
|
||||
await userDB.update(user_id, { has_full_book: true })
|
||||
}
|
||||
|
||||
// 处理分销佣金
|
||||
if (referral_code) {
|
||||
// 查找推荐人
|
||||
const users = await userDB.getAll()
|
||||
const referrer = users.find((u: any) => u.referral_code === referral_code)
|
||||
|
||||
if (referrer) {
|
||||
const commissionRate = 0.9 // 90% 佣金
|
||||
const commissionAmount = amount * commissionRate
|
||||
|
||||
// 查找有效的绑定关系
|
||||
const binding = await distributionDB.getActiveBindingByReferee(user_id)
|
||||
|
||||
if (binding) {
|
||||
// 创建佣金记录
|
||||
await distributionDB.createCommission({
|
||||
id: `commission_${Date.now()}`,
|
||||
binding_id: binding.id,
|
||||
referrer_id: referrer.id,
|
||||
referee_id: user_id,
|
||||
order_id: purchase.id,
|
||||
amount,
|
||||
commission_rate: commissionRate * 100,
|
||||
commission_amount: commissionAmount,
|
||||
status: 'pending'
|
||||
})
|
||||
|
||||
// 更新推荐人收益
|
||||
await userDB.update(referrer.id, {
|
||||
earnings: (referrer.earnings || 0) + commissionAmount,
|
||||
pending_earnings: (referrer.pending_earnings || 0) + commissionAmount
|
||||
})
|
||||
|
||||
// 更新购买记录的推荐人收益
|
||||
purchase.referrer_earnings = commissionAmount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true, purchase })
|
||||
} catch (error: any) {
|
||||
console.error('Create purchase error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
31
app/api/db/settings/route.ts
Normal file
31
app/api/db/settings/route.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { settingsDB } from '@/lib/db'
|
||||
|
||||
// 获取系统设置
|
||||
export async function GET() {
|
||||
try {
|
||||
const settings = await settingsDB.get()
|
||||
return NextResponse.json({ success: true, settings: settings?.data || null })
|
||||
} catch (error: any) {
|
||||
console.error('Get settings error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// 保存系统设置
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json()
|
||||
await settingsDB.update(body)
|
||||
return NextResponse.json({ success: true, message: '设置已保存' })
|
||||
} catch (error: any) {
|
||||
console.error('Save settings error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
114
app/api/db/users/route.ts
Normal file
114
app/api/db/users/route.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { userDB } from '@/lib/db'
|
||||
|
||||
// 获取所有用户
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const id = searchParams.get('id')
|
||||
const phone = searchParams.get('phone')
|
||||
|
||||
if (id) {
|
||||
const user = await userDB.getById(id)
|
||||
return NextResponse.json({ success: true, user })
|
||||
}
|
||||
|
||||
if (phone) {
|
||||
const user = await userDB.getByPhone(phone)
|
||||
return NextResponse.json({ success: true, user })
|
||||
}
|
||||
|
||||
const users = await userDB.getAll()
|
||||
return NextResponse.json({ success: true, users })
|
||||
} catch (error: any) {
|
||||
console.error('Get users 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 { phone, nickname, password, referral_code, referred_by } = body
|
||||
|
||||
// 检查手机号是否已存在
|
||||
const existing = await userDB.getByPhone(phone)
|
||||
if (existing) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '该手机号已注册'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
const user = await userDB.create({
|
||||
id: `user_${Date.now()}`,
|
||||
phone,
|
||||
nickname,
|
||||
password,
|
||||
referral_code: referral_code || `REF${Date.now().toString(36).toUpperCase()}`,
|
||||
referred_by
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true, user })
|
||||
} catch (error: any) {
|
||||
console.error('Create user 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 })
|
||||
}
|
||||
|
||||
await userDB.update(id, updates)
|
||||
const user = await userDB.getById(id)
|
||||
|
||||
return NextResponse.json({ success: true, user })
|
||||
} catch (error: any) {
|
||||
console.error('Update user error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
export async function DELETE(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const id = searchParams.get('id')
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '缺少用户ID'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
await userDB.delete(id)
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error: any) {
|
||||
console.error('Delete user error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
113
app/api/db/withdrawals/route.ts
Normal file
113
app/api/db/withdrawals/route.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { withdrawalDB, userDB } from '@/lib/db'
|
||||
|
||||
// 获取提现记录
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const userId = searchParams.get('user_id')
|
||||
|
||||
if (userId) {
|
||||
const withdrawals = await withdrawalDB.getByUserId(userId)
|
||||
return NextResponse.json({ success: true, withdrawals })
|
||||
}
|
||||
|
||||
const withdrawals = await withdrawalDB.getAll()
|
||||
return NextResponse.json({ success: true, withdrawals })
|
||||
} catch (error: any) {
|
||||
console.error('Get withdrawals 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 { user_id, amount, method, account, name } = body
|
||||
|
||||
// 验证用户余额
|
||||
const user = await userDB.getById(user_id)
|
||||
if (!user) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '用户不存在'
|
||||
}, { status: 404 })
|
||||
}
|
||||
|
||||
if ((user.earnings || 0) < amount) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '余额不足'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
// 创建提现记录
|
||||
const withdrawal = await withdrawalDB.create({
|
||||
id: `withdrawal_${Date.now()}`,
|
||||
user_id,
|
||||
amount,
|
||||
method,
|
||||
account,
|
||||
name,
|
||||
status: 'pending'
|
||||
})
|
||||
|
||||
// 扣除用户余额,增加待提现金额
|
||||
await userDB.update(user_id, {
|
||||
earnings: (user.earnings || 0) - amount,
|
||||
pending_earnings: (user.pending_earnings || 0) + amount
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true, withdrawal })
|
||||
} catch (error: any) {
|
||||
console.error('Create withdrawal 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, status } = body
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: '缺少提现记录ID'
|
||||
}, { status: 400 })
|
||||
}
|
||||
|
||||
await withdrawalDB.updateStatus(id, status)
|
||||
|
||||
// 如果状态是已完成,更新用户的已提现金额
|
||||
if (status === 'completed') {
|
||||
const withdrawals = await withdrawalDB.getAll()
|
||||
const withdrawal = withdrawals.find((w: any) => w.id === id)
|
||||
if (withdrawal) {
|
||||
const user = await userDB.getById(withdrawal.user_id)
|
||||
if (user) {
|
||||
await userDB.update(user.id, {
|
||||
pending_earnings: (user.pending_earnings || 0) - withdrawal.amount,
|
||||
withdrawn_earnings: (user.withdrawn_earnings || 0) + withdrawal.amount
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error: any) {
|
||||
console.error('Update withdrawal status error:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user