feat: 章节数据库化 + 支付配置更新
1. 章节内容迁移到MySQL数据库(67篇文章) 2. 章节API改为从数据库读取,不再依赖book文件夹 3. 新增章节管理API(增删改查) 4. 更新小程序支付AppSecret 5. 整理完整API配置清单
This commit is contained in:
@@ -1,83 +1,12 @@
|
||||
// app/api/book/chapter/[id]/route.ts
|
||||
// 获取章节详情 - 支持小程序和Web端
|
||||
// 获取章节详情 - 从数据库读取,支持小程序和Web端
|
||||
// 更新: 2026-01-25 改为从MySQL数据库读取章节内容
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import matter from 'gray-matter'
|
||||
import { query } from '@/lib/db'
|
||||
|
||||
const BOOK_DIR = path.join(process.cwd(), 'book')
|
||||
|
||||
// 章节ID到文件路径的映射
|
||||
const CHAPTER_MAP: Record<string, { dir: string; file: string; partTitle: string; chapterTitle: string }> = {
|
||||
'preface': { dir: '', file: '序言|为什么我每天早上6点在Soul开播?.md', partTitle: '序言', chapterTitle: '为什么我每天早上6点在Soul开播?' },
|
||||
'epilogue': { dir: '', file: '尾声|这本书的真实目的.md', partTitle: '尾声', chapterTitle: '这本书的真实目的' },
|
||||
'1.1': { dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.1 荷包:电动车出租的被动收入模式.md', partTitle: '第一篇|真实的人', chapterTitle: '1.1 荷包:电动车出租的被动收入模式' },
|
||||
'1.2': { dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.2 老墨:资源整合高手的社交方法.md', partTitle: '第一篇|真实的人', chapterTitle: '1.2 老墨:资源整合高手的社交方法' },
|
||||
'1.3': { dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.3 笑声背后的MBTI:为什么ENTJ适合做资源,INTP适合做系统.md', partTitle: '第一篇|真实的人', chapterTitle: '1.3 笑声背后的MBTI' },
|
||||
'1.4': { dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.4 人性的三角结构:利益、情感、价值观.md', partTitle: '第一篇|真实的人', chapterTitle: '1.4 人性的三角结构' },
|
||||
'1.5': { dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.5 沟通差的问题:为什么你说的别人听不懂.md', partTitle: '第一篇|真实的人', chapterTitle: '1.5 沟通差的问题' },
|
||||
'2.1': { dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.1 相亲故事:你以为找的是人,实际是在找模式.md', partTitle: '第一篇|真实的人', chapterTitle: '2.1 相亲故事' },
|
||||
'2.2': { dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.2 找工作迷茫者:为什么简历解决不了人生.md', partTitle: '第一篇|真实的人', chapterTitle: '2.2 找工作迷茫者' },
|
||||
'2.3': { dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.3 撸运费险:小钱困住大脑的真实心理.md', partTitle: '第一篇|真实的人', chapterTitle: '2.3 撸运费险' },
|
||||
'2.4': { dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.4 游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力.md', partTitle: '第一篇|真实的人', chapterTitle: '2.4 游戏上瘾的年轻人' },
|
||||
'2.5': { dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.5 健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒.md', partTitle: '第一篇|真实的人', chapterTitle: '2.5 健康焦虑' },
|
||||
'3.1': { dir: '第二篇|真实的行业/第3章|电商篇', file: '3.1 3000万流水如何跑出来(退税模式解析).md', partTitle: '第二篇|真实的行业', chapterTitle: '3.1 3000万流水' },
|
||||
'3.2': { dir: '第二篇|真实的行业/第3章|电商篇', file: '3.2 供应链之王 vs 打工人:利润不在前端.md', partTitle: '第二篇|真实的行业', chapterTitle: '3.2 供应链之王' },
|
||||
'3.3': { dir: '第二篇|真实的行业/第3章|电商篇', file: '3.3 社区团购的底层逻辑.md', partTitle: '第二篇|真实的行业', chapterTitle: '3.3 社区团购' },
|
||||
'3.4': { dir: '第二篇|真实的行业/第3章|电商篇', file: '3.4 跨境电商与退税套利.md', partTitle: '第二篇|真实的行业', chapterTitle: '3.4 跨境电商' },
|
||||
'4.1': { dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.1 旅游号:30天10万粉的真实逻辑.md', partTitle: '第二篇|真实的行业', chapterTitle: '4.1 旅游号' },
|
||||
'4.2': { dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.2 做号工厂:如何让一个号变成一个机器.md', partTitle: '第二篇|真实的行业', chapterTitle: '4.2 做号工厂' },
|
||||
'4.3': { dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.3 情绪内容为什么比专业内容更赚钱.md', partTitle: '第二篇|真实的行业', chapterTitle: '4.3 情绪内容' },
|
||||
'4.4': { dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.4 猫与宠物号:为什么宠物赛道永不过时.md', partTitle: '第二篇|真实的行业', chapterTitle: '4.4 猫与宠物号' },
|
||||
'4.5': { dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.5 直播间里的三种人:演员、技术工、系统流.md', partTitle: '第二篇|真实的行业', chapterTitle: '4.5 直播间里的三种人' },
|
||||
'5.1': { dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.1 拍卖行抱朴:一天240万的摇号生意.md', partTitle: '第二篇|真实的行业', chapterTitle: '5.1 拍卖行抱朴' },
|
||||
'5.2': { dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.2 土地拍卖:招拍挂背后的游戏规则.md', partTitle: '第二篇|真实的行业', chapterTitle: '5.2 土地拍卖' },
|
||||
'5.3': { dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.3 地摊经济数字化:一个月900块的餐车生意.md', partTitle: '第二篇|真实的行业', chapterTitle: '5.3 地摊经济' },
|
||||
'5.4': { dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.4 不良资产拍卖:我错过的一个亿佣金.md', partTitle: '第二篇|真实的行业', chapterTitle: '5.4 不良资产拍卖' },
|
||||
'5.5': { dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.5 桶装水李总:跟物业合作的轻资产模式.md', partTitle: '第二篇|真实的行业', chapterTitle: '5.5 桶装水李总' },
|
||||
'6.1': { dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.1 电商财税窗口:2016年的千万级机会.md', partTitle: '第三篇|真实的错误', chapterTitle: '6.1 电商财税窗口' },
|
||||
'6.2': { dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.2 供应链金融:我不懂的杠杆游戏.md', partTitle: '第三篇|真实的错误', chapterTitle: '6.2 供应链金融' },
|
||||
'6.3': { dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.3 内容红利:2019年我为什么没做抖音.md', partTitle: '第三篇|真实的错误', chapterTitle: '6.3 内容红利' },
|
||||
'6.4': { dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.4 数据资产化:我还在观望的未来机会.md', partTitle: '第三篇|真实的错误', chapterTitle: '6.4 数据资产化' },
|
||||
'7.1': { dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.1 投资房年轻人的迷茫:资金 vs 能力.md', partTitle: '第三篇|真实的错误', chapterTitle: '7.1 投资房年轻人' },
|
||||
'7.2': { dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.2 信息差骗局:永远有人靠卖学习赚钱.md', partTitle: '第三篇|真实的错误', chapterTitle: '7.2 信息差骗局' },
|
||||
'7.3': { dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.3 在Soul找恋爱但想赚钱的人.md', partTitle: '第三篇|真实的错误', chapterTitle: '7.3 在Soul找恋爱' },
|
||||
'7.4': { dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.4 创业者的三种死法:冲动、轻信、没结构.md', partTitle: '第三篇|真实的错误', chapterTitle: '7.4 创业者的三种死法' },
|
||||
'7.5': { dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.5 人情生意的终点:关系越多亏得越多.md', partTitle: '第三篇|真实的错误', chapterTitle: '7.5 人情生意' },
|
||||
'8.1': { dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.1 流量杠杆:抖音、Soul、飞书.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '8.1 流量杠杆' },
|
||||
'8.2': { dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.2 价格杠杆:供应链与信息差.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '8.2 价格杠杆' },
|
||||
'8.3': { dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.3 时间杠杆:自动化 + AI.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '8.3 时间杠杆' },
|
||||
'8.4': { dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.4 情绪杠杆:咨询、婚恋、生意场.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '8.4 情绪杠杆' },
|
||||
'8.5': { dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.5 社交杠杆:认识谁比你会什么更重要.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '8.5 社交杠杆' },
|
||||
'8.6': { dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.6 云阿米巴:分不属于自己的钱.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '8.6 云阿米巴' },
|
||||
'9.1': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.1 游戏账号私域:账号即资产.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.1 游戏账号私域' },
|
||||
'9.2': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.2 健康包模式:高复购、高毛利.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.2 健康包模式' },
|
||||
'9.3': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.3 药物私域:长期关系赛道.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.3 药物私域' },
|
||||
'9.4': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.4 残疾机构合作:退税 × AI × 人力成本.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.4 残疾机构合作' },
|
||||
'9.5': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.5 私域银行:粉丝即小股东.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.5 私域银行' },
|
||||
'9.6': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.6 Soul派对房:陌生人成交的最快场景.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.6 Soul派对房' },
|
||||
'9.7': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.7 飞书中台:从聊天到成交的流程化体系.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.7 飞书中台' },
|
||||
'9.8': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.8 餐饮女孩:6万营收、1万利润的死撑生意.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.8 餐饮女孩' },
|
||||
'9.9': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.9 电竞生态:从陪玩到签约到酒店的完整链条.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.9 电竞生态' },
|
||||
'9.10': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.10 淘客大佬:损耗30%的白色通道.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.10 淘客大佬' },
|
||||
'9.11': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.11 蔬菜供应链:农户才是最赚钱的人.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.11 蔬菜供应链' },
|
||||
'9.12': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.12 美业整合:一个人的公司如何月入十万.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.12 美业整合' },
|
||||
'9.13': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.13 AI工具推广:一个隐藏的高利润赛道.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.13 AI工具推广' },
|
||||
'9.14': { dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.14 大健康私域:一个月150万的70后.md', partTitle: '第四篇|真实的赚钱', chapterTitle: '9.14 大健康私域' },
|
||||
'10.1': { dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.1 AI时代:哪些工作会消失,哪些会崛起.md', partTitle: '第五篇|真实的社会', chapterTitle: '10.1 AI时代' },
|
||||
'10.2': { dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.2 一人公司:为什么越来越多人选择单干.md', partTitle: '第五篇|真实的社会', chapterTitle: '10.2 一人公司' },
|
||||
'10.3': { dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.3 为什么链接能力会成为第一价值.md', partTitle: '第五篇|真实的社会', chapterTitle: '10.3 链接能力' },
|
||||
'10.4': { dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.4 新型公司:Soul-飞书-线下的三位一体.md', partTitle: '第五篇|真实的社会', chapterTitle: '10.4 新型公司' },
|
||||
'11.1': { dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.1 私域经济:为什么流量越来越贵.md', partTitle: '第五篇|真实的社会', chapterTitle: '11.1 私域经济' },
|
||||
'11.2': { dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.2 银发经济与孤独经济:两个被忽视的万亿市场.md', partTitle: '第五篇|真实的社会', chapterTitle: '11.2 银发经济' },
|
||||
'11.3': { dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.3 流量红利的终局.md', partTitle: '第五篇|真实的社会', chapterTitle: '11.3 流量红利' },
|
||||
'11.4': { dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.4 大模型 + 供应链的组合拳.md', partTitle: '第五篇|真实的社会', chapterTitle: '11.4 大模型+供应链' },
|
||||
'11.5': { dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.5 社会分层的最终逻辑.md', partTitle: '第五篇|真实的社会', chapterTitle: '11.5 社会分层' },
|
||||
'appendix-1': { dir: '附录', file: '附录1|Soul派对房精选对话.md', partTitle: '附录', chapterTitle: 'Soul派对房精选对话' },
|
||||
'appendix-2': { dir: '附录', file: '附录2|创业者自检清单.md', partTitle: '附录', chapterTitle: '创业者自检清单' },
|
||||
'appendix-3': { dir: '附录', file: '附录3|本书提到的工具和资源.md', partTitle: '附录', chapterTitle: '本书提到的工具和资源' },
|
||||
}
|
||||
// 免费章节列表
|
||||
const FREE_CHAPTERS = ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']
|
||||
|
||||
export async function GET(
|
||||
req: NextRequest,
|
||||
@@ -87,53 +16,41 @@ export async function GET(
|
||||
const chapterId = params.id
|
||||
console.log('[Chapter API] 请求章节:', chapterId)
|
||||
|
||||
// 先从映射表查找
|
||||
const mapping = CHAPTER_MAP[chapterId]
|
||||
let chapterFile: string | null = null
|
||||
let partTitle = ''
|
||||
let chapterTitle = ''
|
||||
// 从数据库查询章节
|
||||
const results = await query(
|
||||
`SELECT id, part_id, part_title, chapter_id, chapter_title, section_title,
|
||||
content, word_count, is_free, price, sort_order, status, updated_at
|
||||
FROM chapters
|
||||
WHERE id = ? AND status = 'published'`,
|
||||
[chapterId]
|
||||
) as any[]
|
||||
|
||||
if (mapping) {
|
||||
const filePath = path.join(BOOK_DIR, mapping.dir, mapping.file)
|
||||
if (fs.existsSync(filePath)) {
|
||||
chapterFile = filePath
|
||||
partTitle = mapping.partTitle
|
||||
chapterTitle = mapping.chapterTitle
|
||||
}
|
||||
}
|
||||
|
||||
// 如果映射找不到,尝试动态查找
|
||||
if (!chapterFile) {
|
||||
chapterFile = findChapterFile(chapterId)
|
||||
}
|
||||
|
||||
if (!chapterFile) {
|
||||
if (!results || results.length === 0) {
|
||||
console.log('[Chapter API] 章节不存在:', chapterId)
|
||||
return NextResponse.json(
|
||||
{ error: '章节不存在', success: false },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
|
||||
const fileContent = fs.readFileSync(chapterFile, 'utf-8')
|
||||
const { data, content } = matter(fileContent)
|
||||
|
||||
// 判断是否免费章节
|
||||
const isFree = isFreeChapter(chapterId)
|
||||
|
||||
console.log('[Chapter API] 返回章节内容:', chapterId, '长度:', content.length)
|
||||
|
||||
const chapter = results[0]
|
||||
const isFree = chapter.is_free || FREE_CHAPTERS.includes(chapterId)
|
||||
|
||||
console.log('[Chapter API] 返回章节内容:', chapterId, '长度:', chapter.content?.length || 0)
|
||||
|
||||
// 返回小程序兼容的格式
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
id: chapterId,
|
||||
title: data.title || chapterTitle || path.basename(chapterFile, '.md'),
|
||||
content: content,
|
||||
partTitle: partTitle || data.category || '',
|
||||
chapterTitle: chapterTitle || data.title || '',
|
||||
words: content.length,
|
||||
updateTime: data.date || fs.statSync(chapterFile).mtime.toISOString(),
|
||||
id: chapter.id,
|
||||
title: chapter.section_title,
|
||||
content: chapter.content,
|
||||
partTitle: chapter.part_title,
|
||||
chapterTitle: chapter.chapter_title,
|
||||
sectionTitle: chapter.section_title,
|
||||
words: chapter.word_count,
|
||||
updateTime: chapter.updated_at,
|
||||
isFree,
|
||||
price: chapter.price,
|
||||
needPurchase: !isFree
|
||||
})
|
||||
} catch (error) {
|
||||
@@ -144,48 +61,3 @@ export async function GET(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 递归查找章节文件
|
||||
function findChapterFile(chapterId: string): string | null {
|
||||
function searchDir(dir: string): string | null {
|
||||
try {
|
||||
const items = fs.readdirSync(dir)
|
||||
|
||||
for (const item of items) {
|
||||
const itemPath = path.join(dir, item)
|
||||
const stat = fs.statSync(itemPath)
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
const result = searchDir(itemPath)
|
||||
if (result) return result
|
||||
} else if (item.endsWith('.md')) {
|
||||
// 检查文件名是否匹配章节ID
|
||||
if (item.startsWith(chapterId + ' ') ||
|
||||
item.includes(chapterId) ||
|
||||
item.replace('.md', '') === chapterId) {
|
||||
return itemPath
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略权限错误
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return searchDir(BOOK_DIR)
|
||||
}
|
||||
|
||||
// 判断是否免费章节
|
||||
function isFreeChapter(chapterId: string): boolean {
|
||||
const freeChapters = [
|
||||
'preface',
|
||||
'epilogue',
|
||||
'1.1',
|
||||
'appendix-1',
|
||||
'appendix-2',
|
||||
'appendix-3'
|
||||
]
|
||||
|
||||
return freeChapters.includes(chapterId)
|
||||
}
|
||||
|
||||
263
app/api/book/chapters/route.ts
Normal file
263
app/api/book/chapters/route.ts
Normal file
@@ -0,0 +1,263 @@
|
||||
// app/api/book/chapters/route.ts
|
||||
// 章节管理API - 支持列表查询、新增、编辑
|
||||
// 开发: 卡若
|
||||
// 日期: 2026-01-25
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { query } from '@/lib/db'
|
||||
|
||||
/**
|
||||
* GET - 获取章节列表
|
||||
* 支持参数:
|
||||
* - partId: 按篇筛选
|
||||
* - status: 按状态筛选 (draft/published/archived)
|
||||
* - page: 页码
|
||||
* - pageSize: 每页数量
|
||||
*/
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const partId = searchParams.get('partId')
|
||||
const status = searchParams.get('status') || 'published'
|
||||
const page = parseInt(searchParams.get('page') || '1')
|
||||
const pageSize = parseInt(searchParams.get('pageSize') || '100')
|
||||
|
||||
let sql = `
|
||||
SELECT id, part_id, part_title, chapter_id, chapter_title, section_title,
|
||||
word_count, is_free, price, sort_order, status, created_at, updated_at
|
||||
FROM chapters
|
||||
WHERE 1=1
|
||||
`
|
||||
const params: any[] = []
|
||||
|
||||
if (partId) {
|
||||
sql += ' AND part_id = ?'
|
||||
params.push(partId)
|
||||
}
|
||||
|
||||
if (status && status !== 'all') {
|
||||
sql += ' AND status = ?'
|
||||
params.push(status)
|
||||
}
|
||||
|
||||
sql += ' ORDER BY sort_order ASC'
|
||||
sql += ' LIMIT ? OFFSET ?'
|
||||
params.push(pageSize, (page - 1) * pageSize)
|
||||
|
||||
const results = await query(sql, params) as any[]
|
||||
|
||||
// 获取总数
|
||||
let countSql = 'SELECT COUNT(*) as total FROM chapters WHERE 1=1'
|
||||
const countParams: any[] = []
|
||||
if (partId) {
|
||||
countSql += ' AND part_id = ?'
|
||||
countParams.push(partId)
|
||||
}
|
||||
if (status && status !== 'all') {
|
||||
countSql += ' AND status = ?'
|
||||
countParams.push(status)
|
||||
}
|
||||
const countResult = await query(countSql, countParams) as any[]
|
||||
const total = countResult[0]?.total || 0
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
list: results,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages: Math.ceil(total / pageSize)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Chapters API] 获取列表失败:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '获取章节列表失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST - 新增章节
|
||||
*/
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json()
|
||||
const {
|
||||
id,
|
||||
partId,
|
||||
partTitle,
|
||||
chapterId,
|
||||
chapterTitle,
|
||||
sectionTitle,
|
||||
content,
|
||||
isFree = false,
|
||||
price = 1,
|
||||
sortOrder,
|
||||
status = 'published'
|
||||
} = body
|
||||
|
||||
// 验证必填字段
|
||||
if (!id || !partId || !partTitle || !chapterId || !chapterTitle || !sectionTitle || !content) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '缺少必填字段' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// 检查ID是否已存在
|
||||
const existing = await query('SELECT id FROM chapters WHERE id = ?', [id]) as any[]
|
||||
if (existing.length > 0) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '章节ID已存在' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// 计算字数
|
||||
const wordCount = content.replace(/\s/g, '').length
|
||||
|
||||
// 计算排序顺序(如果未提供)
|
||||
let order = sortOrder
|
||||
if (order === undefined || order === null) {
|
||||
const maxOrder = await query(
|
||||
'SELECT MAX(sort_order) as maxOrder FROM chapters WHERE part_id = ?',
|
||||
[partId]
|
||||
) as any[]
|
||||
order = (maxOrder[0]?.maxOrder || 0) + 1
|
||||
}
|
||||
|
||||
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, [id, partId, partTitle, chapterId, chapterTitle, sectionTitle, content, wordCount, isFree, isFree ? 0 : price, order, status])
|
||||
|
||||
console.log('[Chapters API] 新增章节成功:', id)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: '章节创建成功',
|
||||
data: { id, wordCount, sortOrder: order }
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Chapters API] 新增章节失败:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '新增章节失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT - 编辑章节
|
||||
*/
|
||||
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 }
|
||||
)
|
||||
}
|
||||
|
||||
// 检查章节是否存在
|
||||
const existing = await query('SELECT id FROM chapters WHERE id = ?', [id]) as any[]
|
||||
if (existing.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '章节不存在' },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
|
||||
// 构建更新语句
|
||||
const allowedFields = ['part_id', 'part_title', 'chapter_id', 'chapter_title', 'section_title', 'content', 'is_free', 'price', 'sort_order', 'status']
|
||||
const fieldMapping: Record<string, string> = {
|
||||
partId: 'part_id',
|
||||
partTitle: 'part_title',
|
||||
chapterId: 'chapter_id',
|
||||
chapterTitle: 'chapter_title',
|
||||
sectionTitle: 'section_title',
|
||||
isFree: 'is_free',
|
||||
sortOrder: 'sort_order'
|
||||
}
|
||||
|
||||
const setClauses: string[] = []
|
||||
const params: any[] = []
|
||||
|
||||
for (const [key, value] of Object.entries(updates)) {
|
||||
const dbField = fieldMapping[key] || key
|
||||
if (allowedFields.includes(dbField) && value !== undefined) {
|
||||
setClauses.push(`${dbField} = ?`)
|
||||
params.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
// 如果更新了content,重新计算字数
|
||||
if (updates.content) {
|
||||
const wordCount = updates.content.replace(/\s/g, '').length
|
||||
setClauses.push('word_count = ?')
|
||||
params.push(wordCount)
|
||||
}
|
||||
|
||||
if (setClauses.length === 0) {
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '没有可更新的字段' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
params.push(id)
|
||||
await query(`UPDATE chapters SET ${setClauses.join(', ')} WHERE id = ?`, params)
|
||||
|
||||
console.log('[Chapters API] 更新章节成功:', id)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: '章节更新成功'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Chapters API] 更新章节失败:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '更新章节失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE - 删除章节(软删除,改状态为archived)
|
||||
*/
|
||||
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 }
|
||||
)
|
||||
}
|
||||
|
||||
// 软删除:改状态为archived
|
||||
await query("UPDATE chapters SET status = 'archived' WHERE id = ?", [id])
|
||||
|
||||
console.log('[Chapters API] 删除章节成功:', id)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: '章节已删除'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('[Chapters API] 删除章节失败:', error)
|
||||
return NextResponse.json(
|
||||
{ success: false, error: '删除章节失败' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,13 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import crypto from 'crypto'
|
||||
|
||||
// 微信支付配置
|
||||
// 微信支付配置 - 2026-01-25 更新
|
||||
// 小程序支付绑定状态: 审核中(申请单ID: 201554696918)
|
||||
const WECHAT_PAY_CONFIG = {
|
||||
appId: 'wxb8bbb2b10dec74aa', // 小程序AppID
|
||||
appSecret: '85d3fa31584d06acdb1de4a597d25b7b', // 小程序AppSecret
|
||||
appSecret: '3c1fb1f63e6e052222bbcead9d07fe0c', // 小程序AppSecret(已更新)
|
||||
mchId: '1318592501', // 商户号
|
||||
mchKey: 'wx3e31b068be59ddc131b068be59ddc2', // API密钥
|
||||
mchKey: 'wx3e31b068be59ddc131b068be59ddc2', // API密钥(v2)
|
||||
notifyUrl: 'https://soul.quwanzhi.com/api/miniprogram/pay/notify', // 支付回调地址
|
||||
}
|
||||
|
||||
|
||||
24
lib/db.ts
24
lib/db.ts
@@ -161,6 +161,30 @@ export async function initDatabase() {
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`)
|
||||
|
||||
// 章节内容表 - 存储书籍所有章节
|
||||
await query(`
|
||||
CREATE TABLE IF NOT EXISTS chapters (
|
||||
id VARCHAR(20) PRIMARY KEY COMMENT '章节ID,如1.1、preface等',
|
||||
part_id VARCHAR(20) NOT NULL COMMENT '所属篇ID,如part-1',
|
||||
part_title VARCHAR(100) NOT NULL COMMENT '篇标题,如第一篇|真实的人',
|
||||
chapter_id VARCHAR(20) NOT NULL COMMENT '所属章ID,如chapter-1',
|
||||
chapter_title VARCHAR(200) NOT NULL COMMENT '章标题,如第1章|人与人之间的底层逻辑',
|
||||
section_title VARCHAR(200) NOT NULL COMMENT '节标题',
|
||||
content LONGTEXT NOT NULL COMMENT '章节正文内容(Markdown格式)',
|
||||
word_count INT DEFAULT 0 COMMENT '字数统计',
|
||||
is_free BOOLEAN DEFAULT FALSE COMMENT '是否免费章节',
|
||||
price DECIMAL(10,2) DEFAULT 1.00 COMMENT '单章价格',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序顺序',
|
||||
status ENUM('draft', 'published', 'archived') DEFAULT 'published' COMMENT '状态',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_part_id (part_id),
|
||||
INDEX idx_chapter_id (chapter_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_sort_order (sort_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`)
|
||||
|
||||
console.log('数据库表结构初始化完成')
|
||||
|
||||
// 插入默认配置
|
||||
|
||||
224
scripts/migrate-chapters-to-db.js
Normal file
224
scripts/migrate-chapters-to-db.js
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* 章节迁移脚本 - 将book文件夹的Markdown文件导入数据库
|
||||
* 运行方式: node scripts/migrate-chapters-to-db.js
|
||||
*
|
||||
* 开发: 卡若
|
||||
* 日期: 2026-01-25
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const mysql = require('mysql2/promise')
|
||||
|
||||
// 数据库配置
|
||||
const DB_CONFIG = {
|
||||
host: '56b4c23f6853c.gz.cdb.myqcloud.com',
|
||||
port: 14413,
|
||||
user: 'cdb_outerroot',
|
||||
password: 'Zhiqun1984',
|
||||
database: 'soul_miniprogram',
|
||||
charset: 'utf8mb4',
|
||||
}
|
||||
|
||||
// Book目录
|
||||
const BOOK_DIR = path.join(process.cwd(), 'book')
|
||||
|
||||
// 免费章节列表
|
||||
const FREE_CHAPTERS = ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']
|
||||
|
||||
// 所有章节配置
|
||||
const CHAPTERS_CONFIG = [
|
||||
// 序言
|
||||
{ id: 'preface', partId: 'intro', partTitle: '序言', chapterId: 'preface', chapterTitle: '序言', sectionTitle: '为什么我每天早上6点在Soul开播?', dir: '', file: '序言|为什么我每天早上6点在Soul开播?.md', sortOrder: 0 },
|
||||
|
||||
// 第一篇 真实的人
|
||||
{ id: '1.1', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-1', chapterTitle: '第1章|人与人之间的底层逻辑', sectionTitle: '荷包:电动车出租的被动收入模式', dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.1 荷包:电动车出租的被动收入模式.md', sortOrder: 1 },
|
||||
{ id: '1.2', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-1', chapterTitle: '第1章|人与人之间的底层逻辑', sectionTitle: '老墨:资源整合高手的社交方法', dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.2 老墨:资源整合高手的社交方法.md', sortOrder: 2 },
|
||||
{ id: '1.3', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-1', chapterTitle: '第1章|人与人之间的底层逻辑', sectionTitle: '笑声背后的MBTI:为什么ENTJ适合做资源,INTP适合做系统', dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.3 笑声背后的MBTI:为什么ENTJ适合做资源,INTP适合做系统.md', sortOrder: 3 },
|
||||
{ id: '1.4', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-1', chapterTitle: '第1章|人与人之间的底层逻辑', sectionTitle: '人性的三角结构:利益、情感、价值观', dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.4 人性的三角结构:利益、情感、价值观.md', sortOrder: 4 },
|
||||
{ id: '1.5', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-1', chapterTitle: '第1章|人与人之间的底层逻辑', sectionTitle: '沟通差的问题:为什么你说的别人听不懂', dir: '第一篇|真实的人/第1章|人与人之间的底层逻辑', file: '1.5 沟通差的问题:为什么你说的别人听不懂.md', sortOrder: 5 },
|
||||
|
||||
{ id: '2.1', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-2', chapterTitle: '第2章|人性困境案例', sectionTitle: '相亲故事:你以为找的是人,实际是在找模式', dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.1 相亲故事:你以为找的是人,实际是在找模式.md', sortOrder: 6 },
|
||||
{ id: '2.2', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-2', chapterTitle: '第2章|人性困境案例', sectionTitle: '找工作迷茫者:为什么简历解决不了人生', dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.2 找工作迷茫者:为什么简历解决不了人生.md', sortOrder: 7 },
|
||||
{ id: '2.3', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-2', chapterTitle: '第2章|人性困境案例', sectionTitle: '撸运费险:小钱困住大脑的真实心理', dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.3 撸运费险:小钱困住大脑的真实心理.md', sortOrder: 8 },
|
||||
{ id: '2.4', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-2', chapterTitle: '第2章|人性困境案例', sectionTitle: '游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力', dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.4 游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力.md', sortOrder: 9 },
|
||||
{ id: '2.5', partId: 'part-1', partTitle: '第一篇|真实的人', chapterId: 'chapter-2', chapterTitle: '第2章|人性困境案例', sectionTitle: '健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒', dir: '第一篇|真实的人/第2章|人性困境案例', file: '2.5 健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒.md', sortOrder: 10 },
|
||||
|
||||
// 第二篇 真实的行业
|
||||
{ id: '3.1', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-3', chapterTitle: '第3章|电商篇', sectionTitle: '3000万流水如何跑出来(退税模式解析)', dir: '第二篇|真实的行业/第3章|电商篇', file: '3.1 3000万流水如何跑出来(退税模式解析).md', sortOrder: 11 },
|
||||
{ id: '3.2', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-3', chapterTitle: '第3章|电商篇', sectionTitle: '供应链之王 vs 打工人:利润不在前端', dir: '第二篇|真实的行业/第3章|电商篇', file: '3.2 供应链之王 vs 打工人:利润不在前端.md', sortOrder: 12 },
|
||||
{ id: '3.3', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-3', chapterTitle: '第3章|电商篇', sectionTitle: '社区团购的底层逻辑', dir: '第二篇|真实的行业/第3章|电商篇', file: '3.3 社区团购的底层逻辑.md', sortOrder: 13 },
|
||||
{ id: '3.4', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-3', chapterTitle: '第3章|电商篇', sectionTitle: '跨境电商与退税套利', dir: '第二篇|真实的行业/第3章|电商篇', file: '3.4 跨境电商与退税套利.md', sortOrder: 14 },
|
||||
|
||||
{ id: '4.1', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-4', chapterTitle: '第4章|内容商业篇', sectionTitle: '旅游号:30天10万粉的真实逻辑', dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.1 旅游号:30天10万粉的真实逻辑.md', sortOrder: 15 },
|
||||
{ id: '4.2', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-4', chapterTitle: '第4章|内容商业篇', sectionTitle: '做号工厂:如何让一个号变成一个机器', dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.2 做号工厂:如何让一个号变成一个机器.md', sortOrder: 16 },
|
||||
{ id: '4.3', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-4', chapterTitle: '第4章|内容商业篇', sectionTitle: '情绪内容为什么比专业内容更赚钱', dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.3 情绪内容为什么比专业内容更赚钱.md', sortOrder: 17 },
|
||||
{ id: '4.4', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-4', chapterTitle: '第4章|内容商业篇', sectionTitle: '猫与宠物号:为什么宠物赛道永不过时', dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.4 猫与宠物号:为什么宠物赛道永不过时.md', sortOrder: 18 },
|
||||
{ id: '4.5', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-4', chapterTitle: '第4章|内容商业篇', sectionTitle: '直播间里的三种人:演员、技术工、系统流', dir: '第二篇|真实的行业/第4章|内容商业篇', file: '4.5 直播间里的三种人:演员、技术工、系统流.md', sortOrder: 19 },
|
||||
|
||||
{ id: '5.1', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-5', chapterTitle: '第5章|传统行业篇', sectionTitle: '拍卖行抱朴:一天240万的摇号生意', dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.1 拍卖行抱朴:一天240万的摇号生意.md', sortOrder: 20 },
|
||||
{ id: '5.2', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-5', chapterTitle: '第5章|传统行业篇', sectionTitle: '土地拍卖:招拍挂背后的游戏规则', dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.2 土地拍卖:招拍挂背后的游戏规则.md', sortOrder: 21 },
|
||||
{ id: '5.3', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-5', chapterTitle: '第5章|传统行业篇', sectionTitle: '地摊经济数字化:一个月900块的餐车生意', dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.3 地摊经济数字化:一个月900块的餐车生意.md', sortOrder: 22 },
|
||||
{ id: '5.4', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-5', chapterTitle: '第5章|传统行业篇', sectionTitle: '不良资产拍卖:我错过的一个亿佣金', dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.4 不良资产拍卖:我错过的一个亿佣金.md', sortOrder: 23 },
|
||||
{ id: '5.5', partId: 'part-2', partTitle: '第二篇|真实的行业', chapterId: 'chapter-5', chapterTitle: '第5章|传统行业篇', sectionTitle: '桶装水李总:跟物业合作的轻资产模式', dir: '第二篇|真实的行业/第5章|传统行业篇', file: '5.5 桶装水李总:跟物业合作的轻资产模式.md', sortOrder: 24 },
|
||||
|
||||
// 第三篇 真实的错误
|
||||
{ id: '6.1', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-6', chapterTitle: '第6章|我人生错过的4件大钱', sectionTitle: '电商财税窗口:2016年的千万级机会', dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.1 电商财税窗口:2016年的千万级机会.md', sortOrder: 25 },
|
||||
{ id: '6.2', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-6', chapterTitle: '第6章|我人生错过的4件大钱', sectionTitle: '供应链金融:我不懂的杠杆游戏', dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.2 供应链金融:我不懂的杠杆游戏.md', sortOrder: 26 },
|
||||
{ id: '6.3', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-6', chapterTitle: '第6章|我人生错过的4件大钱', sectionTitle: '内容红利:2019年我为什么没做抖音', dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.3 内容红利:2019年我为什么没做抖音.md', sortOrder: 27 },
|
||||
{ id: '6.4', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-6', chapterTitle: '第6章|我人生错过的4件大钱', sectionTitle: '数据资产化:我还在观望的未来机会', dir: '第三篇|真实的错误/第6章|我人生错过的4件大钱', file: '6.4 数据资产化:我还在观望的未来机会.md', sortOrder: 28 },
|
||||
|
||||
{ id: '7.1', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-7', chapterTitle: '第7章|别人犯的错误', sectionTitle: '投资房年轻人的迷茫:资金 vs 能力', dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.1 投资房年轻人的迷茫:资金 vs 能力.md', sortOrder: 29 },
|
||||
{ id: '7.2', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-7', chapterTitle: '第7章|别人犯的错误', sectionTitle: '信息差骗局:永远有人靠卖学习赚钱', dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.2 信息差骗局:永远有人靠卖学习赚钱.md', sortOrder: 30 },
|
||||
{ id: '7.3', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-7', chapterTitle: '第7章|别人犯的错误', sectionTitle: '在Soul找恋爱但想赚钱的人', dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.3 在Soul找恋爱但想赚钱的人.md', sortOrder: 31 },
|
||||
{ id: '7.4', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-7', chapterTitle: '第7章|别人犯的错误', sectionTitle: '创业者的三种死法:冲动、轻信、没结构', dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.4 创业者的三种死法:冲动、轻信、没结构.md', sortOrder: 32 },
|
||||
{ id: '7.5', partId: 'part-3', partTitle: '第三篇|真实的错误', chapterId: 'chapter-7', chapterTitle: '第7章|别人犯的错误', sectionTitle: '人情生意的终点:关系越多亏得越多', dir: '第三篇|真实的错误/第7章|别人犯的错误', file: '7.5 人情生意的终点:关系越多亏得越多.md', sortOrder: 33 },
|
||||
|
||||
// 第四篇 真实的赚钱
|
||||
{ id: '8.1', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-8', chapterTitle: '第8章|底层结构', sectionTitle: '流量杠杆:抖音、Soul、飞书', dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.1 流量杠杆:抖音、Soul、飞书.md', sortOrder: 34 },
|
||||
{ id: '8.2', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-8', chapterTitle: '第8章|底层结构', sectionTitle: '价格杠杆:供应链与信息差', dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.2 价格杠杆:供应链与信息差.md', sortOrder: 35 },
|
||||
{ id: '8.3', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-8', chapterTitle: '第8章|底层结构', sectionTitle: '时间杠杆:自动化 + AI', dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.3 时间杠杆:自动化 + AI.md', sortOrder: 36 },
|
||||
{ id: '8.4', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-8', chapterTitle: '第8章|底层结构', sectionTitle: '情绪杠杆:咨询、婚恋、生意场', dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.4 情绪杠杆:咨询、婚恋、生意场.md', sortOrder: 37 },
|
||||
{ id: '8.5', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-8', chapterTitle: '第8章|底层结构', sectionTitle: '社交杠杆:认识谁比你会什么更重要', dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.5 社交杠杆:认识谁比你会什么更重要.md', sortOrder: 38 },
|
||||
{ id: '8.6', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-8', chapterTitle: '第8章|底层结构', sectionTitle: '云阿米巴:分不属于自己的钱', dir: '第四篇|真实的赚钱/第8章|底层结构', file: '8.6 云阿米巴:分不属于自己的钱.md', sortOrder: 39 },
|
||||
|
||||
{ id: '9.1', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '游戏账号私域:账号即资产', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.1 游戏账号私域:账号即资产.md', sortOrder: 40 },
|
||||
{ id: '9.2', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '健康包模式:高复购、高毛利', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.2 健康包模式:高复购、高毛利.md', sortOrder: 41 },
|
||||
{ id: '9.3', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '药物私域:长期关系赛道', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.3 药物私域:长期关系赛道.md', sortOrder: 42 },
|
||||
{ id: '9.4', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '残疾机构合作:退税 × AI × 人力成本', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.4 残疾机构合作:退税 × AI × 人力成本.md', sortOrder: 43 },
|
||||
{ id: '9.5', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '私域银行:粉丝即小股东', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.5 私域银行:粉丝即小股东.md', sortOrder: 44 },
|
||||
{ id: '9.6', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: 'Soul派对房:陌生人成交的最快场景', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.6 Soul派对房:陌生人成交的最快场景.md', sortOrder: 45 },
|
||||
{ id: '9.7', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '飞书中台:从聊天到成交的流程化体系', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.7 飞书中台:从聊天到成交的流程化体系.md', sortOrder: 46 },
|
||||
{ id: '9.8', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '餐饮女孩:6万营收、1万利润的死撑生意', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.8 餐饮女孩:6万营收、1万利润的死撑生意.md', sortOrder: 47 },
|
||||
{ id: '9.9', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '电竞生态:从陪玩到签约到酒店的完整链条', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.9 电竞生态:从陪玩到签约到酒店的完整链条.md', sortOrder: 48 },
|
||||
{ id: '9.10', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '淘客大佬:损耗30%的白色通道', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.10 淘客大佬:损耗30%的白色通道.md', sortOrder: 49 },
|
||||
{ id: '9.11', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '蔬菜供应链:农户才是最赚钱的人', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.11 蔬菜供应链:农户才是最赚钱的人.md', sortOrder: 50 },
|
||||
{ id: '9.12', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '美业整合:一个人的公司如何月入十万', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.12 美业整合:一个人的公司如何月入十万.md', sortOrder: 51 },
|
||||
{ id: '9.13', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: 'AI工具推广:一个隐藏的高利润赛道', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.13 AI工具推广:一个隐藏的高利润赛道.md', sortOrder: 52 },
|
||||
{ id: '9.14', partId: 'part-4', partTitle: '第四篇|真实的赚钱', chapterId: 'chapter-9', chapterTitle: '第9章|我在Soul上亲访的赚钱案例', sectionTitle: '大健康私域:一个月150万的70后', dir: '第四篇|真实的赚钱/第9章|我在Soul上亲访的赚钱案例', file: '9.14 大健康私域:一个月150万的70后.md', sortOrder: 53 },
|
||||
|
||||
// 第五篇 真实的社会
|
||||
{ id: '10.1', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-10', chapterTitle: '第10章|未来职业的变化趋势', sectionTitle: 'AI时代:哪些工作会消失,哪些会崛起', dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.1 AI时代:哪些工作会消失,哪些会崛起.md', sortOrder: 54 },
|
||||
{ id: '10.2', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-10', chapterTitle: '第10章|未来职业的变化趋势', sectionTitle: '一人公司:为什么越来越多人选择单干', dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.2 一人公司:为什么越来越多人选择单干.md', sortOrder: 55 },
|
||||
{ id: '10.3', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-10', chapterTitle: '第10章|未来职业的变化趋势', sectionTitle: '为什么链接能力会成为第一价值', dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.3 为什么链接能力会成为第一价值.md', sortOrder: 56 },
|
||||
{ id: '10.4', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-10', chapterTitle: '第10章|未来职业的变化趋势', sectionTitle: '新型公司:Soul-飞书-线下的三位一体', dir: '第五篇|真实的社会/第10章|未来职业的变化趋势', file: '10.4 新型公司:Soul-飞书-线下的三位一体.md', sortOrder: 57 },
|
||||
|
||||
{ id: '11.1', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-11', chapterTitle: '第11章|中国社会商业生态的未来', sectionTitle: '私域经济:为什么流量越来越贵', dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.1 私域经济:为什么流量越来越贵.md', sortOrder: 58 },
|
||||
{ id: '11.2', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-11', chapterTitle: '第11章|中国社会商业生态的未来', sectionTitle: '银发经济与孤独经济:两个被忽视的万亿市场', dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.2 银发经济与孤独经济:两个被忽视的万亿市场.md', sortOrder: 59 },
|
||||
{ id: '11.3', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-11', chapterTitle: '第11章|中国社会商业生态的未来', sectionTitle: '流量红利的终局', dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.3 流量红利的终局.md', sortOrder: 60 },
|
||||
{ id: '11.4', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-11', chapterTitle: '第11章|中国社会商业生态的未来', sectionTitle: '大模型 + 供应链的组合拳', dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.4 大模型 + 供应链的组合拳.md', sortOrder: 61 },
|
||||
{ id: '11.5', partId: 'part-5', partTitle: '第五篇|真实的社会', chapterId: 'chapter-11', chapterTitle: '第11章|中国社会商业生态的未来', sectionTitle: '社会分层的最终逻辑', dir: '第五篇|真实的社会/第11章|中国社会商业生态的未来', file: '11.5 社会分层的最终逻辑.md', sortOrder: 62 },
|
||||
|
||||
// 尾声
|
||||
{ id: 'epilogue', partId: 'outro', partTitle: '尾声', chapterId: 'epilogue', chapterTitle: '尾声', sectionTitle: '这本书的真实目的', dir: '', file: '尾声|这本书的真实目的.md', sortOrder: 63 },
|
||||
|
||||
// 附录
|
||||
{ id: 'appendix-1', partId: 'appendix', partTitle: '附录', chapterId: 'appendix', chapterTitle: '附录', sectionTitle: 'Soul派对房精选对话', dir: '附录', file: '附录1|Soul派对房精选对话.md', sortOrder: 64 },
|
||||
{ id: 'appendix-2', partId: 'appendix', partTitle: '附录', chapterId: 'appendix', chapterTitle: '附录', sectionTitle: '创业者自检清单', dir: '附录', file: '附录2|创业者自检清单.md', sortOrder: 65 },
|
||||
{ id: 'appendix-3', partId: 'appendix', partTitle: '附录', chapterId: 'appendix', chapterTitle: '附录', sectionTitle: '本书提到的工具和资源', dir: '附录', file: '附录3|本书提到的工具和资源.md', sortOrder: 66 },
|
||||
]
|
||||
|
||||
async function main() {
|
||||
console.log('🚀 开始迁移章节内容到数据库...')
|
||||
console.log(`📁 Book目录: ${BOOK_DIR}`)
|
||||
console.log(`📊 共${CHAPTERS_CONFIG.length}个章节\n`)
|
||||
|
||||
// 先连接MySQL(不指定数据库),创建数据库
|
||||
const initConnection = await mysql.createConnection({
|
||||
host: DB_CONFIG.host,
|
||||
port: DB_CONFIG.port,
|
||||
user: DB_CONFIG.user,
|
||||
password: DB_CONFIG.password,
|
||||
charset: DB_CONFIG.charset,
|
||||
})
|
||||
|
||||
await initConnection.execute(`CREATE DATABASE IF NOT EXISTS soul_miniprogram CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`)
|
||||
console.log('✅ 数据库 soul_miniprogram 创建/确认成功')
|
||||
await initConnection.end()
|
||||
|
||||
// 连接数据库
|
||||
const connection = await mysql.createConnection(DB_CONFIG)
|
||||
console.log('✅ 数据库连接成功\n')
|
||||
|
||||
// 创建表(如果不存在)
|
||||
await connection.execute(`
|
||||
CREATE TABLE IF NOT EXISTS chapters (
|
||||
id VARCHAR(20) PRIMARY KEY COMMENT '章节ID,如1.1、preface等',
|
||||
part_id VARCHAR(20) NOT NULL COMMENT '所属篇ID,如part-1',
|
||||
part_title VARCHAR(100) NOT NULL COMMENT '篇标题,如第一篇|真实的人',
|
||||
chapter_id VARCHAR(20) NOT NULL COMMENT '所属章ID,如chapter-1',
|
||||
chapter_title VARCHAR(200) NOT NULL COMMENT '章标题,如第1章|人与人之间的底层逻辑',
|
||||
section_title VARCHAR(200) NOT NULL COMMENT '节标题',
|
||||
content LONGTEXT NOT NULL COMMENT '章节正文内容(Markdown格式)',
|
||||
word_count INT DEFAULT 0 COMMENT '字数统计',
|
||||
is_free BOOLEAN DEFAULT FALSE COMMENT '是否免费章节',
|
||||
price DECIMAL(10,2) DEFAULT 1.00 COMMENT '单章价格',
|
||||
sort_order INT DEFAULT 0 COMMENT '排序顺序',
|
||||
status ENUM('draft', 'published', 'archived') DEFAULT 'published' COMMENT '状态',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_part_id (part_id),
|
||||
INDEX idx_chapter_id (chapter_id),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_sort_order (sort_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`)
|
||||
console.log('✅ chapters表创建/确认成功\n')
|
||||
|
||||
// 迁移章节
|
||||
let successCount = 0
|
||||
let errorCount = 0
|
||||
|
||||
for (const config of CHAPTERS_CONFIG) {
|
||||
const filePath = path.join(BOOK_DIR, config.dir, config.file)
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(`⚠️ 文件不存在: ${config.id} - ${config.file}`)
|
||||
errorCount++
|
||||
continue
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
const wordCount = content.replace(/\s/g, '').length
|
||||
const isFree = FREE_CHAPTERS.includes(config.id)
|
||||
|
||||
// 使用 REPLACE INTO 实现更新或插入
|
||||
await connection.execute(`
|
||||
REPLACE INTO chapters (id, part_id, part_title, chapter_id, chapter_title, section_title, content, word_count, is_free, price, sort_order, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'published')
|
||||
`, [
|
||||
config.id,
|
||||
config.partId,
|
||||
config.partTitle,
|
||||
config.chapterId,
|
||||
config.chapterTitle,
|
||||
config.sectionTitle,
|
||||
content,
|
||||
wordCount,
|
||||
isFree,
|
||||
isFree ? 0 : 1,
|
||||
config.sortOrder
|
||||
])
|
||||
|
||||
console.log(`✅ ${config.id}: ${config.sectionTitle} (${wordCount}字${isFree ? ' 免费' : ''})`)
|
||||
successCount++
|
||||
} catch (error) {
|
||||
console.log(`❌ ${config.id}: ${error.message}`)
|
||||
errorCount++
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(50))
|
||||
console.log(`📊 迁移完成: 成功 ${successCount} 个, 失败 ${errorCount} 个`)
|
||||
console.log('='.repeat(50))
|
||||
|
||||
// 查询验证
|
||||
const [rows] = await connection.execute('SELECT COUNT(*) as count FROM chapters')
|
||||
console.log(`\n📚 数据库中共有 ${rows[0].count} 个章节`)
|
||||
|
||||
await connection.end()
|
||||
console.log('\n✅ 数据库连接已关闭')
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
205
开发文档/API/配置清单-完整版.md
Normal file
205
开发文档/API/配置清单-完整版.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# Soul创业实验 - API密钥与配置清单
|
||||
|
||||
> 最后更新: 2026-01-25
|
||||
> 维护人: 卡若
|
||||
> ⚠️ 本文件包含敏感信息,请勿公开
|
||||
|
||||
---
|
||||
|
||||
## 一、企业信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **企业名称** | 泉州市卡若网络技术有限公司 |
|
||||
| **联系电话** | 15880802661 |
|
||||
| **微信号** | 28533368 |
|
||||
| **邮箱** | zhiqun@qq.com / zhengzhiqun@vip.qq.com |
|
||||
|
||||
---
|
||||
|
||||
## 二、微信生态
|
||||
|
||||
### 2.1 小程序(Soul创业实验)
|
||||
|
||||
| 项目 | 值 | 备注 |
|
||||
|:---|:---|:---|
|
||||
| **AppID** | `wxb8bbb2b10dec74aa` | 小程序ID |
|
||||
| **AppSecret** | `3c1fb1f63e6e052222bbcead9d07fe0c` | 小程序密钥 |
|
||||
| **支付绑定状态** | 🟡 审核中 | 2026-01-25 09:43:59 提交 |
|
||||
|
||||
### 2.2 服务号(玩值)
|
||||
|
||||
| 项目 | 值 | 备注 |
|
||||
|:---|:---|:---|
|
||||
| **AppID** | `wx7c0dbf34ddba300d` | 服务号AppID |
|
||||
| **AppSecret** | `f865ef18c43dfea6cbe3b1f1aebdb82e` | 服务号密钥 |
|
||||
| **支付绑定状态** | ✅ 已绑定 | 绑定AppID: wx3e31b068be59ddc1 |
|
||||
|
||||
### 2.3 网站应用
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **AppID** | `wx432c93e275548671` |
|
||||
| **AppSecret** | `25b7e7fdb7998e5107e242ebb6ddabd0` |
|
||||
|
||||
### 2.4 微信支付
|
||||
|
||||
| 项目 | 值 | 备注 |
|
||||
|:---|:---|:---|
|
||||
| **商户号** | `1318592501` | 主体: 泉州市卡若网络技术有限公司 |
|
||||
| **API密钥(v2)** | `wx3e31b068be59ddc131b068be59ddc2` | 32位 |
|
||||
| **MP文件验证码** | `SP8AfZJyAvprRORT` | |
|
||||
| **支付回调地址** | `https://soul.quwanzhi.com/api/miniprogram/pay/notify` | |
|
||||
|
||||
#### 已绑定AppID
|
||||
|
||||
| AppID | 类型 | 状态 |
|
||||
|:---|:---|:---|
|
||||
| `wx3e31b068be59ddc1` | 服务号 | ✅ 已关联 |
|
||||
| `wxb8bbb2b10dec74aa` | 小程序 | 🟡 审核中 |
|
||||
|
||||
---
|
||||
|
||||
## 三、支付宝
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **PID** | `2088511801157159` |
|
||||
| **MD5密钥** | `lz6ey1h3kl9zqkgtjz3avb5gk37wzbrp` |
|
||||
| **账户** | zhengzhiqun@vip.qq.com |
|
||||
|
||||
---
|
||||
|
||||
## 四、云服务
|
||||
|
||||
### 4.1 腾讯云
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **APPID** | `1251077262` |
|
||||
| **SecretId** | `AKIDjc6yO3nPeOuK2OKsJPBBVbTiiz0aPNHl` |
|
||||
| **SecretKey** | *(见用户规则)* |
|
||||
|
||||
### 4.2 阿里云
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **AccessKey ID** | `LTAI5t9zkiWmFtHG8qmtdysW` |
|
||||
| **AccessKey Secret** | `xxjXnZGLNvA2zDkj0aEBSQm3XZAaro` |
|
||||
|
||||
---
|
||||
|
||||
## 五、数据库
|
||||
|
||||
### 5.1 腾讯云MySQL(生产环境)
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **主机** | `56b4c23f6853c.gz.cdb.myqcloud.com` |
|
||||
| **端口** | `14413` |
|
||||
| **数据库** | `soul_miniprogram` |
|
||||
| **用户名** | `cdb_outerroot` |
|
||||
| **密码** | `Zhiqun1984` |
|
||||
| **字符集** | `utf8mb4` |
|
||||
|
||||
#### 数据库表
|
||||
|
||||
| 表名 | 说明 |
|
||||
|:---|:---|
|
||||
| `users` | 用户表 |
|
||||
| `orders` | 订单表 |
|
||||
| `referral_bindings` | 推广绑定关系 |
|
||||
| `match_records` | 匹配记录 |
|
||||
| `system_config` | 系统配置 |
|
||||
| `chapters` | **章节内容表(新)** |
|
||||
|
||||
### 5.2 卡若私域数据库(内网)
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **主机** | `10.88.182.62` |
|
||||
| **端口** | `3306` |
|
||||
| **用户名** | `root` |
|
||||
| **密码** | `Vtka(agu)-1` |
|
||||
|
||||
---
|
||||
|
||||
## 六、AI服务
|
||||
|
||||
### 6.1 v0 API
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **API地址** | `https://api.v0.dev/v1` |
|
||||
| **API Key** | `v1:C6mw1SlvXsJdlO4VFEXSQEVf:519gA0DPqIMbjvfMh7CXf4B2` |
|
||||
| **默认模型** | `claude-opus` |
|
||||
|
||||
---
|
||||
|
||||
## 七、开发工具
|
||||
|
||||
### 7.1 GitHub
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **Token** | `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` |
|
||||
|
||||
---
|
||||
|
||||
## 八、项目部署信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|:---|:---|
|
||||
| **域名** | `soul.quwanzhi.com` |
|
||||
| **协议** | HTTPS |
|
||||
| **服务器** | 宝塔面板 |
|
||||
| **部署方式** | GitHub Webhook 自动部署 |
|
||||
|
||||
---
|
||||
|
||||
## 九、邮箱账户
|
||||
|
||||
| 邮箱 | 密码 |
|
||||
|:---|:---|
|
||||
| `zhiqun@qq.com` | `#vtk();1984` |
|
||||
| `zhengzhiqun@vip.qq.com` | `#vtk();1984` |
|
||||
| `15880802661@qq.com` | `#vtk();1984` |
|
||||
|
||||
---
|
||||
|
||||
## 十、配置代码引用
|
||||
|
||||
### 小程序支付配置
|
||||
|
||||
```typescript
|
||||
// lib/payment/wechat-miniprogram.ts
|
||||
const WECHAT_PAY_CONFIG = {
|
||||
appId: 'wxb8bbb2b10dec74aa', // 小程序AppID
|
||||
appSecret: '3c1fb1f63e6e052222bbcead9d07fe0c', // 小程序AppSecret
|
||||
mchId: '1318592501', // 商户号
|
||||
mchKey: 'wx3e31b068be59ddc131b068be59ddc2', // API密钥(v2)
|
||||
notifyUrl: 'https://soul.quwanzhi.com/api/miniprogram/pay/notify',
|
||||
}
|
||||
```
|
||||
|
||||
### 数据库配置
|
||||
|
||||
```typescript
|
||||
// lib/db.ts
|
||||
const DB_CONFIG = {
|
||||
host: '56b4c23f6853c.gz.cdb.myqcloud.com',
|
||||
port: 14413,
|
||||
user: 'cdb_outerroot',
|
||||
password: 'Zhiqun1984',
|
||||
database: 'soul_miniprogram',
|
||||
charset: 'utf8mb4',
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 更新日志
|
||||
|
||||
| 日期 | 更新内容 |
|
||||
|:---|:---|
|
||||
| 2026-01-25 | 创建完整配置清单;小程序支付绑定申请中;章节表迁移完成 |
|
||||
Reference in New Issue
Block a user