diff --git a/.v0rc.json b/.v0rc.json deleted file mode 100644 index 63f889c3..00000000 --- a/.v0rc.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "defaultModel": "claude-opus", - "framework": "next-app-router", - "styling": "tailwind", - "componentLibrary": "shadcn/ui", - "typescript": true, - "rules": [ - "Use modular components", - "Avoid placeholder logic", - "Production-ready code only", - "Follow Design Guidelines", - "所有页面组件保持一致性", - "使用现有导航系统", - "遵循毛玻璃设计风格", - "精简文字,增加流程图" - ] -} diff --git a/app/admin/chapters/page.tsx b/app/admin/chapters/page.tsx new file mode 100644 index 00000000..4ae054d0 --- /dev/null +++ b/app/admin/chapters/page.tsx @@ -0,0 +1,293 @@ +'use client' + +import { useState, useEffect } from 'react' +import Link from 'next/link' + +interface Section { + id: string + title: string + price: number + isFree: boolean + status: string +} + +interface Chapter { + id: string + title: string + sections?: Section[] + price?: number + isFree?: boolean + status?: string +} + +interface Part { + id: string + title: string + type: string + chapters: Chapter[] +} + +interface Stats { + totalSections: number + freeSections: number + paidSections: number + totalParts: number +} + +export default function ChaptersManagement() { + const [structure, setStructure] = useState([]) + const [stats, setStats] = useState(null) + const [loading, setLoading] = useState(true) + const [expandedParts, setExpandedParts] = useState([]) + const [editingSection, setEditingSection] = useState(null) + const [editPrice, setEditPrice] = useState(1) + + useEffect(() => { + loadChapters() + }, []) + + const loadChapters = async () => { + try { + const response = await fetch('/api/admin/chapters') + const data = await response.json() + if (data.success) { + setStructure(data.data.structure) + setStats(data.data.stats) + } + } catch (error) { + console.error('加载章节失败:', error) + } finally { + setLoading(false) + } + } + + const togglePart = (partId: string) => { + setExpandedParts(prev => + prev.includes(partId) + ? prev.filter(id => id !== partId) + : [...prev, partId] + ) + } + + const handleUpdatePrice = async (sectionId: string) => { + try { + const response = await fetch('/api/admin/chapters', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + action: 'updatePrice', + chapterId: sectionId, + data: { price: editPrice } + }) + }) + const result = await response.json() + if (result.success) { + alert('价格更新成功') + setEditingSection(null) + loadChapters() + } + } catch (error) { + console.error('更新价格失败:', error) + } + } + + const handleToggleFree = async (sectionId: string, currentFree: boolean) => { + try { + const response = await fetch('/api/admin/chapters', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + action: 'toggleFree', + chapterId: sectionId, + data: { isFree: !currentFree } + }) + }) + const result = await response.json() + if (result.success) { + alert('状态更新成功') + loadChapters() + } + } catch (error) { + console.error('更新状态失败:', error) + } + } + + if (loading) { + return ( +
+
加载中...
+
+ ) + } + + return ( +
+ {/* 导航栏 */} +
+
+
+ ← 返回 +

章节管理

+
+
+ + +
+
+
+ +
+ {/* 统计卡片 */} + {stats && ( +
+
+
{stats.totalSections}
+
总章节数
+
+
+
{stats.freeSections}
+
免费章节
+
+
+
{stats.paidSections}
+
付费章节
+
+
+
{stats.totalParts}
+
篇章数
+
+
+ )} + + {/* 章节列表 */} +
+ {structure.map(part => ( +
+ {/* 篇标题 */} +
togglePart(part.id)} + > +
+ + {part.type === 'preface' ? '📖' : + part.type === 'epilogue' ? '🎬' : + part.type === 'appendix' ? '📎' : '📚'} + + {part.title} + + ({part.chapters.reduce((acc, ch) => acc + (ch.sections?.length || 1), 0)} 节) + +
+ + {expandedParts.includes(part.id) ? '▲' : '▼'} + +
+ + {/* 章节内容 */} + {expandedParts.includes(part.id) && ( +
+ {part.chapters.map(chapter => ( +
+ {/* 章标题 */} + {chapter.sections ? ( + <> +
+ {chapter.title} +
+ {/* 小节列表 */} +
+ {chapter.sections.map(section => ( +
+
+ + {section.isFree ? '🔓' : '🔒'} + + {section.id} + {section.title} +
+
+ {editingSection === section.id ? ( +
+ setEditPrice(Number(e.target.value))} + className="w-20 px-2 py-1 bg-white/10 border border-white/20 rounded text-white" + min="0" + step="0.1" + /> + + +
+ ) : ( + <> + + {section.isFree ? '免费' : `¥${section.price}`} + + + + + )} +
+
+ ))} +
+ + ) : ( +
+
+ + {chapter.isFree ? '🔓' : '🔒'} + + {chapter.title} +
+ + {chapter.isFree ? '免费' : `¥${chapter.price || 1}`} + +
+ )} +
+ ))} +
+ )} +
+ ))} +
+
+
+ ) +} \ No newline at end of file diff --git a/app/api/admin/chapters/route.ts b/app/api/admin/chapters/route.ts new file mode 100644 index 00000000..a8ef4a11 --- /dev/null +++ b/app/api/admin/chapters/route.ts @@ -0,0 +1,320 @@ +/** + * 章节管理API - 后台管理功能 + * 用于管理书籍章节、价格、状态等 + */ + +import { NextResponse } from 'next/server' +import fs from 'fs' +import path from 'path' + +// 获取书籍目录 +const BOOK_DIR = path.join(process.cwd(), 'book') + +/** + * GET - 获取所有章节列表 + */ +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url) + const includeContent = searchParams.get('content') === 'true' + + // 定义书籍结构 + const bookStructure = [ + { + id: 'part-preface', + title: '序言', + type: 'preface', + chapters: [ + { + id: 'preface', + title: '序言|为什么我每天早上6点在Soul开播?', + price: 0, + isFree: true, + status: 'published', + file: '序言|为什么我每天早上6点在Soul开播?.md' + } + ] + }, + { + id: 'part-1', + title: '第一篇|真实的人', + type: 'part', + chapters: [ + { + id: 'chapter-1', + title: '第1章|人与人之间的底层逻辑', + sections: [ + { id: '1.1', title: '荷包:电动车出租的被动收入模式', price: 1, isFree: true, status: 'published' }, + { id: '1.2', title: '老墨:资源整合高手的社交方法', price: 1, isFree: false, status: 'published' }, + { id: '1.3', title: '笑声背后的MBTI:为什么ENTJ适合做资源,INTP适合做系统', price: 1, isFree: false, status: 'published' }, + { id: '1.4', title: '人性的三角结构:利益、情感、价值观', price: 1, isFree: false, status: 'published' }, + { id: '1.5', title: '沟通差的问题:为什么你说的别人听不懂', price: 1, isFree: false, status: 'published' } + ] + }, + { + id: 'chapter-2', + title: '第2章|人性困境案例', + sections: [ + { id: '2.1', title: '相亲故事:你以为找的是人,实际是在找模式', price: 1, isFree: false, status: 'published' }, + { id: '2.2', title: '找工作迷茫者:为什么简历解决不了人生', price: 1, isFree: false, status: 'published' }, + { id: '2.3', title: '撸运费险:小钱困住大脑的真实心理', price: 1, isFree: false, status: 'published' }, + { id: '2.4', title: '游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力', price: 1, isFree: false, status: 'published' }, + { id: '2.5', title: '健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒', price: 1, isFree: false, status: 'published' } + ] + } + ] + }, + { + id: 'part-2', + title: '第二篇|真实的行业', + type: 'part', + chapters: [ + { + id: 'chapter-3', + title: '第3章|电商篇', + sections: [ + { id: '3.1', title: '3000万流水如何跑出来(退税模式解析)', price: 1, isFree: false, status: 'published' }, + { id: '3.2', title: '供应链之王 vs 打工人:利润不在前端', price: 1, isFree: false, status: 'published' }, + { id: '3.3', title: '社区团购的底层逻辑', price: 1, isFree: false, status: 'published' }, + { id: '3.4', title: '跨境电商与退税套利', price: 1, isFree: false, status: 'published' } + ] + }, + { + id: 'chapter-4', + title: '第4章|内容商业篇', + sections: [ + { id: '4.1', title: '旅游号:30天10万粉的真实逻辑', price: 1, isFree: false, status: 'published' }, + { id: '4.2', title: '做号工厂:如何让一个号变成一个机器', price: 1, isFree: false, status: 'published' }, + { id: '4.3', title: '情绪内容为什么比专业内容更赚钱', price: 1, isFree: false, status: 'published' }, + { id: '4.4', title: '猫与宠物号:为什么宠物赛道永不过时', price: 1, isFree: false, status: 'published' }, + { id: '4.5', title: '直播间里的三种人:演员、技术工、系统流', price: 1, isFree: false, status: 'published' } + ] + }, + { + id: 'chapter-5', + title: '第5章|传统行业篇', + sections: [ + { id: '5.1', title: '拍卖行抱朴:一天240万的摇号生意', price: 1, isFree: false, status: 'published' }, + { id: '5.2', title: '土地拍卖:招拍挂背后的游戏规则', price: 1, isFree: false, status: 'published' }, + { id: '5.3', title: '地摊经济数字化:一个月900块的餐车生意', price: 1, isFree: false, status: 'published' }, + { id: '5.4', title: '不良资产拍卖:我错过的一个亿佣金', price: 1, isFree: false, status: 'published' }, + { id: '5.5', title: '桶装水李总:跟物业合作的轻资产模式', price: 1, isFree: false, status: 'published' } + ] + } + ] + }, + { + id: 'part-3', + title: '第三篇|真实的错误', + type: 'part', + chapters: [ + { + id: 'chapter-6', + title: '第6章|我人生错过的4件大钱', + sections: [ + { id: '6.1', title: '电商财税窗口:2016年的千万级机会', price: 1, isFree: false, status: 'published' }, + { id: '6.2', title: '供应链金融:我不懂的杠杆游戏', price: 1, isFree: false, status: 'published' }, + { id: '6.3', title: '内容红利:2019年我为什么没做抖音', price: 1, isFree: false, status: 'published' }, + { id: '6.4', title: '数据资产化:我还在观望的未来机会', price: 1, isFree: false, status: 'published' } + ] + }, + { + id: 'chapter-7', + title: '第7章|别人犯的错误', + sections: [ + { id: '7.1', title: '投资房年轻人的迷茫:资金 vs 能力', price: 1, isFree: false, status: 'published' }, + { id: '7.2', title: '信息差骗局:永远有人靠卖学习赚钱', price: 1, isFree: false, status: 'published' }, + { id: '7.3', title: '在Soul找恋爱但想赚钱的人', price: 1, isFree: false, status: 'published' }, + { id: '7.4', title: '创业者的三种死法:冲动、轻信、没结构', price: 1, isFree: false, status: 'published' }, + { id: '7.5', title: '人情生意的终点:关系越多亏得越多', price: 1, isFree: false, status: 'published' } + ] + } + ] + }, + { + id: 'part-4', + title: '第四篇|真实的赚钱', + type: 'part', + chapters: [ + { + id: 'chapter-8', + title: '第8章|底层结构', + sections: [ + { id: '8.1', title: '流量杠杆:抖音、Soul、飞书', price: 1, isFree: false, status: 'published' }, + { id: '8.2', title: '价格杠杆:供应链与信息差', price: 1, isFree: false, status: 'published' }, + { id: '8.3', title: '时间杠杆:自动化 + AI', price: 1, isFree: false, status: 'published' }, + { id: '8.4', title: '情绪杠杆:咨询、婚恋、生意场', price: 1, isFree: false, status: 'published' }, + { id: '8.5', title: '社交杠杆:认识谁比你会什么更重要', price: 1, isFree: false, status: 'published' }, + { id: '8.6', title: '云阿米巴:分不属于自己的钱', price: 1, isFree: false, status: 'published' } + ] + }, + { + id: 'chapter-9', + title: '第9章|我在Soul上亲访的赚钱案例', + sections: [ + { id: '9.1', title: '游戏账号私域:账号即资产', price: 1, isFree: false, status: 'published' }, + { id: '9.2', title: '健康包模式:高复购、高毛利', price: 1, isFree: false, status: 'published' }, + { id: '9.3', title: '药物私域:长期关系赛道', price: 1, isFree: false, status: 'published' }, + { id: '9.4', title: '残疾机构合作:退税 × AI × 人力成本', price: 1, isFree: false, status: 'published' }, + { id: '9.5', title: '私域银行:粉丝即小股东', price: 1, isFree: false, status: 'published' }, + { id: '9.6', title: 'Soul派对房:陌生人成交的最快场景', price: 1, isFree: false, status: 'published' }, + { id: '9.7', title: '飞书中台:从聊天到成交的流程化体系', price: 1, isFree: false, status: 'published' }, + { id: '9.8', title: '餐饮女孩:6万营收、1万利润的死撑生意', price: 1, isFree: false, status: 'published' }, + { id: '9.9', title: '电竞生态:从陪玩到签约到酒店的完整链条', price: 1, isFree: false, status: 'published' }, + { id: '9.10', title: '淘客大佬:损耗30%的白色通道', price: 1, isFree: false, status: 'published' }, + { id: '9.11', title: '蔬菜供应链:农户才是最赚钱的人', price: 1, isFree: false, status: 'published' }, + { id: '9.12', title: '美业整合:一个人的公司如何月入十万', price: 1, isFree: false, status: 'published' }, + { id: '9.13', title: 'AI工具推广:一个隐藏的高利润赛道', price: 1, isFree: false, status: 'published' }, + { id: '9.14', title: '大健康私域:一个月150万的70后', price: 1, isFree: false, status: 'published' } + ] + } + ] + }, + { + id: 'part-5', + title: '第五篇|真实的社会', + type: 'part', + chapters: [ + { + id: 'chapter-10', + title: '第10章|未来职业的变化趋势', + sections: [ + { id: '10.1', title: 'AI时代:哪些工作会消失,哪些会崛起', price: 1, isFree: false, status: 'published' }, + { id: '10.2', title: '一人公司:为什么越来越多人选择单干', price: 1, isFree: false, status: 'published' }, + { id: '10.3', title: '为什么链接能力会成为第一价值', price: 1, isFree: false, status: 'published' }, + { id: '10.4', title: '新型公司:Soul-飞书-线下的三位一体', price: 1, isFree: false, status: 'published' } + ] + }, + { + id: 'chapter-11', + title: '第11章|中国社会商业生态的未来', + sections: [ + { id: '11.1', title: '私域经济:为什么流量越来越贵', price: 1, isFree: false, status: 'published' }, + { id: '11.2', title: '银发经济与孤独经济:两个被忽视的万亿市场', price: 1, isFree: false, status: 'published' }, + { id: '11.3', title: '流量红利的终局', price: 1, isFree: false, status: 'published' }, + { id: '11.4', title: '大模型 + 供应链的组合拳', price: 1, isFree: false, status: 'published' }, + { id: '11.5', title: '社会分层的最终逻辑', price: 1, isFree: false, status: 'published' } + ] + } + ] + }, + { + id: 'part-epilogue', + title: '尾声', + type: 'epilogue', + chapters: [ + { + id: 'epilogue', + title: '尾声|这本书的真实目的', + price: 0, + isFree: true, + status: 'published', + file: '尾声|这本书的真实目的.md' + } + ] + }, + { + id: 'part-appendix', + title: '附录', + type: 'appendix', + chapters: [ + { id: 'appendix-1', title: '附录1|Soul派对房精选对话', price: 0, isFree: true, status: 'published' }, + { id: 'appendix-2', title: '附录2|创业者自检清单', price: 0, isFree: true, status: 'published' }, + { id: 'appendix-3', title: '附录3|本书提到的工具和资源', price: 0, isFree: true, status: 'published' } + ] + } + ] + + // 计算统计数据 + let totalSections = 0 + let freeSections = 0 + let paidSections = 0 + + bookStructure.forEach(part => { + if (part.chapters) { + part.chapters.forEach(chapter => { + if (chapter.sections) { + totalSections += chapter.sections.length + chapter.sections.forEach(s => { + if (s.isFree) freeSections++ + else paidSections++ + }) + } else { + totalSections++ + if (chapter.isFree) freeSections++ + else paidSections++ + } + }) + } + }) + + return NextResponse.json({ + success: true, + data: { + structure: bookStructure, + stats: { + totalSections, + freeSections, + paidSections, + totalParts: bookStructure.length + } + } + }) + + } catch (error) { + console.error('[AdminChapters] 获取章节失败:', error) + return NextResponse.json({ + success: false, + error: '获取章节失败' + }, { status: 500 }) + } +} + +/** + * POST - 更新章节设置 + */ +export async function POST(request: Request) { + try { + const body = await request.json() + const { action, chapterId, data } = body + + console.log('[AdminChapters] 更新章节:', { action, chapterId }) + + switch (action) { + case 'updatePrice': + // 更新章节价格 + // TODO: 保存到数据库 + return NextResponse.json({ + success: true, + data: { message: '价格更新成功', chapterId, price: data.price } + }) + + case 'toggleFree': + // 切换免费状态 + return NextResponse.json({ + success: true, + data: { message: '免费状态更新成功', chapterId, isFree: data.isFree } + }) + + case 'updateStatus': + // 更新发布状态 + return NextResponse.json({ + success: true, + data: { message: '发布状态更新成功', chapterId, status: data.status } + }) + + default: + return NextResponse.json({ + success: false, + error: '未知操作' + }, { status: 400 }) + } + + } catch (error) { + console.error('[AdminChapters] 更新章节失败:', error) + return NextResponse.json({ + success: false, + error: '更新章节失败' + }, { status: 500 }) + } +} \ No newline at end of file diff --git a/lib/db.ts b/lib/db.ts index 901e6dbb..492f9532 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -5,12 +5,12 @@ import mysql from 'mysql2/promise' -// 数据库配置 +// 腾讯云外网数据库配置 const DB_CONFIG = { - host: '10.88.182.62', - port: 3306, - user: 'root', - password: 'Vtka(agu)-1', + host: '56b4c23f6853c.gz.cdb.myqcloud.com', + port: 14413, + user: 'cdb_outerroot', + password: 'Zhiqun1984', database: 'soul_miniprogram', charset: 'utf8mb4', timezone: '+08:00', diff --git a/miniprogram/pages/chapters/chapters.wxss b/miniprogram/pages/chapters/chapters.wxss index 7b9468d3..64e9bdfa 100644 --- a/miniprogram/pages/chapters/chapters.wxss +++ b/miniprogram/pages/chapters/chapters.wxss @@ -336,15 +336,15 @@ } .section-icon { - width: 32rpx; - height: 32rpx; - min-width: 32rpx; - font-size: 24rpx; + width: 36rpx; + height: 36rpx; + min-width: 36rpx; + font-size: 28rpx; flex-shrink: 0; - display: inline-flex; + display: flex; align-items: center; justify-content: center; - margin-right: 4rpx; + line-height: 1; } .icon-unlocked { @@ -361,8 +361,11 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - line-height: 32rpx; + line-height: 36rpx; flex: 1; + height: 36rpx; + display: flex; + align-items: center; } .section-right { diff --git a/miniprogram/pages/my/my.wxml b/miniprogram/pages/my/my.wxml index 6939c57d..5ed3d60e 100644 --- a/miniprogram/pages/my/my.wxml +++ b/miniprogram/pages/my/my.wxml @@ -11,31 +11,16 @@ - - - - - 👤 - - - - - - - 0 - 已购章节 - - - 0 - 推荐好友 - - - -- - 待领收益 - + + @@ -71,17 +56,6 @@ - - - - 🎁 - - 推广赚收益 - 登录后查看详情 - - - 立即登录 - @@ -100,29 +74,6 @@ - - - - - - 📚 - 购买章节 - - - - - - - - ℹ️ - 关于我们 - - - - - - - diff --git a/miniprogram/pages/my/my.wxss b/miniprogram/pages/my/my.wxss index b93b5b17..e202deff 100644 --- a/miniprogram/pages/my/my.wxss +++ b/miniprogram/pages/my/my.wxss @@ -113,6 +113,69 @@ margin-top: 4rpx; } +/* ===== 登录卡片样式 ===== */ +.login-card { + min-height: 400rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.login-prompt { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 40rpx 0; + width: 100%; +} + +.login-icon-large { + font-size: 80rpx; + margin-bottom: 32rpx; +} + +.login-title { + font-size: 36rpx; + font-weight: 600; + color: #ffffff; + margin-bottom: 16rpx; +} + +.login-desc { + font-size: 26rpx; + color: rgba(255, 255, 255, 0.5); + margin-bottom: 48rpx; + line-height: 1.6; +} + +.btn-wechat-large { + display: flex; + align-items: center; + justify-content: center; + gap: 16rpx; + width: 80%; + padding: 28rpx 0; + background: linear-gradient(135deg, #07C160 0%, #06AD56 100%); + border-radius: 48rpx; + border: none; + color: #ffffff; + font-size: 32rpx; + font-weight: 600; +} + +.btn-wechat-large .btn-icon { + width: 48rpx; + height: 48rpx; + background: rgba(255, 255, 255, 0.2); + border-radius: 8rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 28rpx; + font-weight: 700; +} + .user-name { font-size: 36rpx; font-weight: 600; diff --git a/miniprogram/pages/read/read.js b/miniprogram/pages/read/read.js index 9d5a4e65..5be6745f 100644 --- a/miniprogram/pages/read/read.js +++ b/miniprogram/pages/read/read.js @@ -363,6 +363,20 @@ ${id === 'preface' || id === 'epilogue' || id.startsWith('appendix') || id === ' // 处理支付 - 调用真实微信支付接口 async processPayment(type, sectionId, amount) { + // 检查是否已购买(避免重复购买) + if (type === 'section' && sectionId) { + const purchasedSections = app.globalData.purchasedSections || [] + if (purchasedSections.includes(sectionId)) { + wx.showToast({ title: '已购买过此章节', icon: 'none' }) + return + } + } + + if (type === 'fullbook' && app.globalData.hasFullBook) { + wx.showToast({ title: '已购买全书', icon: 'none' }) + return + } + this.setData({ isPaying: true }) try { @@ -370,17 +384,23 @@ ${id === 'preface' || id === 'epilogue' || id.startsWith('appendix') || id === ' let openId = app.globalData.openId || wx.getStorageSync('openId') if (!openId) { - console.log('[Pay] 需要先获取openId') + console.log('[Pay] 需要先获取openId,尝试静默获取') openId = await app.getOpenId() if (!openId) { - wx.showModal({ - title: '提示', - content: '需要登录后才能支付,请先登录', - showCancel: false - }) - this.setData({ showLoginModal: true, isPaying: false }) - return + // openId获取失败,但已登录用户可以使用用户ID替代 + if (app.globalData.isLoggedIn && app.globalData.userInfo?.id) { + console.log('[Pay] 使用用户ID作为替代') + openId = app.globalData.userInfo.id + } else { + wx.showModal({ + title: '提示', + content: '需要登录后才能支付,请先登录', + showCancel: false + }) + this.setData({ showLoginModal: true, isPaying: false }) + return + } } } diff --git a/v0使用指南.md b/v0使用指南.md deleted file mode 100644 index 61561b91..00000000 --- a/v0使用指南.md +++ /dev/null @@ -1,124 +0,0 @@ -# v0 使用指南 - Claude Opus 配置 - -## ✅ 配置完成 - -已成功配置 v0 使用 **claude-opus** 模型,配置包括: - -1. **全局配置**:Cursor 设置文件已更新 -2. **项目配置**:`.v0rc.json` 已创建 -3. **规则文件**:`.cursorrules` 已创建 - ---- - -## 🚀 如何使用 v0 - -### 方式1:Composer(推荐) - -1. 打开 Cursor Composer - - **Mac**: `Cmd + K` 或 `Cmd + I` - - **Windows/Linux**: `Ctrl + K` 或 `Ctrl + I` - -2. 输入指令(会自动使用 claude-opus): - ``` - @v0 生成一个用户登录页面,使用shadcn/ui组件 - ``` - -### 方式2:Chat 对话 - -1. 打开 Cursor Chat - - **Mac**: `Cmd + L` - - **Windows/Linux**: `Ctrl + L` - -2. 直接输入需求: - ``` - 使用v0生成一个响应式的产品展示卡片组件 - ``` - -### 方式3:快捷命令 - -1. 选中代码块 -2. 右键 → "Generate with v0" -3. 或使用快捷键:`Cmd + Shift + L`(Mac) - ---- - -## 📝 使用示例 - -### 示例1:生成完整页面 - -``` -@v0 使用claude-opus生成/tech-review-0121页面的优化版本: -- 结构:6个板块(目标、视频切片、账号迁移、分销、结算、复盘) -- 风格:深色科技风格 -- 特点:少文字、多流程图、多图片 -- 框架:Next.js App Router -- 样式:Tailwind CSS -``` - -### 示例2:组件优化 - -``` -@v0 优化这个组件,增加响应式设计和加载状态 -``` - -### 示例3:快速原型 - -``` -@v0 turbo 快速生成一个简单的表单组件 -``` - ---- - -## ⚙️ 模型切换 - -如果需要临时切换模型,可以在指令中指定: - -- `@v0 claude-opus` - 复杂推理(默认) -- `@v0 v0-1.5-md` - 生产级代码 -- `@v0 v0-1.5-turbo` - 快速原型 -- `@v0 claude-3.5-sonnet` - 通用任务 - ---- - -## 🎯 当前项目配置 - -根据 `.v0rc.json` 配置: - -- **默认模型**: claude-opus -- **框架**: Next.js App Router -- **样式**: Tailwind CSS -- **组件库**: shadcn/ui -- **语言**: TypeScript - ---- - -## 💡 最佳实践 - -1. **明确需求**:生成前先说明具体需求 -2. **分步生成**:复杂功能分步骤生成 -3. **代码审查**:生成后检查代码质量 -4. **保持一致性**:遵循项目设计规范 - ---- - -## 🔍 验证配置 - -在 Cursor 中测试: - -``` -@v0 生成一个简单的Hello World组件,使用TypeScript和Tailwind -``` - -如果成功生成代码,说明配置正确! - ---- - -## 📚 相关文件 - -- **全局配置**: `~/Library/Application Support/Cursor/User/settings.json` -- **项目配置**: `.v0rc.json` -- **规则文件**: `.cursorrules` - ---- - -**配置完成!现在可以在 Cursor 中使用 v0 的 claude-opus 模型了!** 🎉 diff --git a/vercel.json b/vercel.json deleted file mode 100644 index 8bc6a5ac..00000000 --- a/vercel.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "buildCommand": "next build", - "devCommand": "next dev", - "installCommand": "npm install", - "framework": "nextjs", - "regions": ["hkg1", "sin1"], - "env": { - "ALIPAY_PARTNER_ID": "@alipay_partner_id", - "ALIPAY_KEY": "@alipay_key", - "WECHAT_APP_ID": "@wechat_app_id", - "WECHAT_APP_SECRET": "@wechat_app_secret", - "WECHAT_MCH_ID": "@wechat_mch_id", - "WECHAT_API_KEY": "@wechat_api_key" - }, - "headers": [ - { - "source": "/api/(.*)", - "headers": [ - { - "key": "Access-Control-Allow-Origin", - "value": "*" - }, - { - "key": "Access-Control-Allow-Methods", - "value": "GET, POST, PUT, DELETE, OPTIONS" - }, - { - "key": "Access-Control-Allow-Headers", - "value": "Content-Type, Authorization" - } - ] - } - ] -} diff --git a/开发文档/1、需求/小程序改造TDD需求方案_v1.0.md b/开发文档/1、需求/小程序改造TDD需求方案_v1.0.md new file mode 100644 index 00000000..a2a6a4eb --- /dev/null +++ b/开发文档/1、需求/小程序改造TDD需求方案_v1.0.md @@ -0,0 +1,402 @@ +# 小程序改造 TDD需求方案 v1.0 + +**创建日期**:2026年1月23日 +**创建人**:卡若AI +**状态**:待开发 + +--- + +## 一、需求摘要 + +**一句话定位**:优化Soul创业实验小程序的用户体验,增强核心功能,提升变现转化率。 + +**核心闭环**: +``` +用户打开小程序 → 搜索/浏览内容 → 阅读(进度同步)→ 付费购买 → 分销推广 → 自动提现 + ↓ + 匹配合伙人 → 查看档案/认证 → 建立合作 +``` + +--- + +## 二、项目背景 + +| 维度 | 内容 | +|:---|:---| +| **项目名称** | 一场Soul的创业实验 - 小程序改造 | +| **项目阶段** | 已上线,功能迭代 | +| **核心目标** | 交互体验优化 + 功能增强 | +| **验收人** | 卡若 | +| **代码位置** | `/Users/karuo/Documents/开发/3、自营项目/一场soul的创业实验/miniprogram/` | + +### 当前问题 + +| 问题类型 | 具体表现 | +|:---|:---| +| 交互不顺畅 | 登录/支付流程分散,代码重复,体验不一致 | +| 导航混乱 | switchTab/navigateTo混用,用户易迷路 | +| 功能缺失 | 无搜索、无进度同步、无自动提现、合伙人匹配弱 | +| 数据不同步 | 购买后需手动刷新才能看到状态变化 | + +--- + +## 三、功能范围 + +### 3.1 核心功能(本期开发) + +| 模块 | 功能点 | 优先级 | 工作量预估 | +|:---|:---|:---|:---| +| **全站搜索** | 搜索章节标题、内容、合伙人 | P0 | 中 | +| **阅读进度同步** | 小程序↔网页端同步,多设备同步 | P0 | 中 | +| **自动提现** | 分销收益达阈值自动提现 | P1 | 高 | +| **合伙人档案** | 合伙人详细档案、认证体系 | P1 | 高 | +| **登录流程统一** | 全局登录组件,状态管理优化 | P0 | 低 | +| **支付流程简化** | 抽离支付模块,统一调用接口 | P0 | 中 | +| **导航结构优化** | 增加TabBar页面,统一跳转规则 | P1 | 中 | +| **数据实时同步** | 购买/操作后实时更新UI | P0 | 低 | + +### 3.2 本期不做 + +| 功能 | 原因 | +|:---|:---| +| 听书/TTS朗读 | 需要额外音频资源和API,优先级低 | +| 批注/划线/笔记 | 开发量大,后续版本考虑 | +| 拼团/砍价 | 营销功能复杂,当前分销模式已够用 | +| 聊天/私信 | 需要IM基础设施,成本高 | +| 离线阅读 | 小程序限制,技术复杂度高 | + +--- + +## 四、功能详细设计 + +### 4.1 全站搜索 + +**用户场景**:用户想快速找到某个话题、某个案例、或某个合伙人。 + +**搜索范围**: +- 章节标题(62个章节) +- 章节内容(全文索引) +- 合伙人(昵称、行业、标签) + +**交互设计**: +``` +首页顶部搜索入口 → 搜索页(独立页面) + ↓ + 输入关键词 + ↓ + Tab切换:全部 | 章节 | 合伙人 + ↓ + 点击结果跳转 +``` + +**技术方案**: +- 前端:新增 `/pages/search/search` 页面 +- 后端:新增 `/api/search` 接口,支持分页 +- 数据库:章节内容建立全文索引,合伙人表增加搜索字段 + +--- + +### 4.2 阅读进度同步 + +**用户场景**:用户在手机小程序看到第3章,换到电脑网页端继续看,能自动跳到上次位置。 + +**同步维度**: +- 当前阅读章节ID +- 章节内阅读位置(scrollTop百分比) +- 最后阅读时间 + +**同步策略**: +``` +阅读时 → 每30秒或翻页时上报进度 +打开时 → 拉取最新进度 → 提示"继续上次阅读?" +``` + +**技术方案**: +- 前端:阅读页增加进度上报逻辑,onHide/onUnload时同步 +- 后端:新增 `/api/reading-progress` 接口(GET/POST) +- 数据库:新增 `reading_progress` 表 + +**数据结构**: +```sql +CREATE TABLE reading_progress ( + id INT PRIMARY KEY AUTO_INCREMENT, + user_id VARCHAR(64) NOT NULL, + section_id VARCHAR(32) NOT NULL, + scroll_percent DECIMAL(5,2) DEFAULT 0, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_user_section (user_id, section_id) +); +``` + +--- + +### 4.3 自动提现 + +**用户场景**:分销用户累积佣金达到100元,系统自动打款到微信零钱。 + +**业务规则**: +| 规则 | 说明 | +|:---|:---| +| 提现阈值 | 默认100元(可后台配置) | +| 提现时间 | 每日凌晨2点检查并执行 | +| 提现方式 | 微信企业付款到零钱 | +| 手续费 | 平台承担 | +| 失败处理 | 记录日志,人工处理 | + +**交互设计**: +``` +个人中心 → 推广中心 → 收益明细 + ↓ + 显示"自动提现已开启" + 显示"满100元自动到账" + ↓ + 提现记录列表 +``` + +**技术方案**: +- 前端:推广中心页面增加自动提现开关和记录 +- 后端: + - 新增 `/api/withdrawal/auto-config` 接口(配置) + - 新增 `/api/withdrawal/records` 接口(记录) + - 新增定时任务(每日检查并执行提现) +- 微信支付:使用企业付款到零钱API + +--- + +### 4.4 合伙人档案/认证 + +**用户场景**:用户想找靠谱的合伙人,需要看到对方的详细背景和资质认证。 + +**档案字段**: +| 字段 | 类型 | 说明 | +|:---|:---|:---| +| 基础信息 | 必填 | 昵称、头像、一句话介绍 | +| 行业领域 | 必填 | 电商/内容/传统行业/技术/其他 | +| 所在城市 | 必填 | 省市选择 | +| 资源标签 | 多选 | 流量/供应链/资金/技术/人脉 | +| 需求标签 | 多选 | 找流量/找供应链/找资金/找技术/找合伙人 | +| 详细介绍 | 选填 | 200字以内 | +| 联系方式 | 认证后可见 | 微信号 | + +**认证体系**: +| 认证等级 | 条件 | 权益 | +|:---|:---|:---| +| 未认证 | 默认 | 只能看基础信息 | +| 手机认证 | 绑定手机号 | 可查看他人手机认证信息 | +| 实名认证 | 提交身份证 | 显示"已实名"标识,可查看微信号 | +| 付费认证 | 购买全书 | 显示"书友"标识,优先匹配 | + +**交互设计**: +``` +匹配页 → 合伙人列表(卡片式) + ↓ + 点击查看档案 + ↓ + 档案详情页 + ↓ + 未认证提示 → 去认证 → 认证流程 +``` + +**技术方案**: +- 前端: + - 改造 `/pages/match/match` 为合伙人列表 + - 新增 `/pages/partner-profile/partner-profile` 档案详情页 + - 新增 `/pages/partner-edit/partner-edit` 档案编辑页 +- 后端: + - 新增 `/api/partner/list` 接口(列表+筛选) + - 新增 `/api/partner/profile` 接口(详情) + - 新增 `/api/partner/update` 接口(更新档案) + - 新增 `/api/partner/verify` 接口(认证) +- 数据库:新增 `partner_profile` 表 + +--- + +### 4.5 交互优化 + +#### 4.5.1 登录流程统一 + +**当前问题**: +- 首页、阅读页、我的页面各自实现登录弹窗 +- 代码重复,样式不一致 + +**改造方案**: +``` +1. 新建全局登录组件 /components/global-login/ +2. app.js 增加全局登录方法 app.showLogin() +3. 各页面调用 app.showLogin() 即可 +4. 登录成功后通过事件广播通知各页面刷新 +``` + +#### 4.5.2 支付流程简化 + +**当前问题**: +- 阅读页 `read.js` 支付相关代码300+行 +- 真实支付和模拟支付逻辑混杂 + +**改造方案**: +``` +1. 新建支付工具 /utils/payment.js(已有,需重构) +2. 封装统一支付方法: + - payment.paySection(sectionId) 购买章节 + - payment.payFullBook() 购买全书 +3. 内部处理所有逻辑(创建订单、调起支付、更新状态) +4. 各页面只需一行调用 +``` + +#### 4.5.3 导航结构优化 + +**当前TabBar**:首页 | 匹配 | 我的(3个) + +**优化后TabBar**:首页 | 目录 | 搜索 | 合伙人 | 我的(5个) + +**页面层级规则**: +| 类型 | 页面 | 跳转方式 | +|:---|:---|:---| +| TabBar页 | 首页、目录、搜索、合伙人、我的 | `wx.switchTab` | +| 二级页 | 阅读、档案详情、推广中心、设置 | `wx.navigateTo` | +| 弹窗 | 登录、支付确认、分享 | 组件弹窗 | + +#### 4.5.4 数据实时同步 + +**改造方案**: +``` +1. 使用全局状态管理(基于 app.globalData + 事件机制) +2. 关键操作后广播事件: + - 登录成功 → 'login-success' + - 购买成功 → 'purchase-success' + - 进度更新 → 'progress-update' +3. 各页面监听事件,自动刷新UI +``` + +--- + +## 五、技术约束 + +| 维度 | 约束 | +|:---|:---| +| **小程序框架** | 微信原生小程序(不使用uni-app/Taro) | +| **后端框架** | Next.js API Routes | +| **数据库** | MySQL(已有实例) | +| **部署环境** | 宝塔面板 + GitHub Webhook自动部署 | +| **微信支付** | 已对接,企业付款需单独申请 | + +--- + +## 六、异常处理规则 + +| 异常场景 | 处理方式 | +|:---|:---| +| 搜索无结果 | 显示"暂无相关内容",推荐热门章节 | +| 进度同步失败 | 本地缓存,下次启动重试 | +| 自动提现失败 | 记录日志,标记待人工处理,通知用户 | +| 合伙人认证失败 | 显示失败原因,引导重新提交 | +| 网络异常 | 统一显示"网络异常,请重试",支持重试 | +| 登录态过期 | 自动刷新token,失败则弹出登录框 | + +--- + +## 七、测试用例清单 + +### 7.1 全站搜索 + +| 用例ID | 场景 | 输入 | 期望输出 | +|:---|:---|:---|:---| +| S01 | 搜索章节标题 | "电动车" | 返回1.1章节 | +| S02 | 搜索章节内容 | "私域银行" | 返回包含该词的章节列表 | +| S03 | 搜索合伙人 | "电商" | 返回行业为电商的合伙人 | +| S04 | 空关键词搜索 | "" | 显示热门推荐 | +| S05 | 无结果搜索 | "xyz123" | 显示"暂无相关内容" | + +### 7.2 阅读进度同步 + +| 用例ID | 场景 | 操作 | 期望结果 | +|:---|:---|:---|:---| +| R01 | 进度上报 | 阅读到50%位置 | 服务端记录scroll_percent=50 | +| R02 | 进度恢复 | 重新打开章节 | 自动滚动到50%位置 | +| R03 | 跨设备同步 | 手机读到3章,电脑打开 | 电脑显示"继续阅读第3章?" | +| R04 | 网络断开 | 离线阅读 | 本地缓存进度,联网后同步 | + +### 7.3 自动提现 + +| 用例ID | 场景 | 条件 | 期望结果 | +|:---|:---|:---|:---| +| W01 | 达到阈值 | 余额=100元 | 凌晨自动提现到微信 | +| W02 | 未达阈值 | 余额=50元 | 不触发提现 | +| W03 | 提现失败 | 微信接口异常 | 记录失败日志,通知管理员 | +| W04 | 关闭自动提现 | 用户手动关闭 | 不触发自动提现 | + +### 7.4 合伙人档案 + +| 用例ID | 场景 | 操作 | 期望结果 | +|:---|:---|:---|:---| +| P01 | 创建档案 | 填写必填字段并保存 | 档案创建成功,显示在列表 | +| P02 | 查看档案 | 点击合伙人卡片 | 跳转档案详情页 | +| P03 | 未认证查看 | 未认证用户查看他人微信 | 提示"认证后可查看" | +| P04 | 筛选合伙人 | 选择"电商"+"找流量" | 只显示符合条件的合伙人 | + +### 7.5 交互优化 + +| 用例ID | 场景 | 操作 | 期望结果 | +|:---|:---|:---|:---| +| U01 | 全局登录 | 任意页面点击需登录功能 | 弹出统一登录框 | +| U02 | 登录后刷新 | 登录成功 | 当前页面自动刷新用户状态 | +| U03 | 购买后更新 | 购买章节成功 | 立即显示"已购买",无需刷新 | +| U04 | TabBar切换 | 点击目录Tab | 切换到目录页,选中状态正确 | + +--- + +## 八、验收标准 + +| 验收项 | 标准 | 验收人 | +|:---|:---|:---| +| 功能完整 | 全部P0功能可用,P1功能90%可用 | 卡若 | +| 交互流畅 | 页面切换无卡顿,操作响应<500ms | 卡若 | +| 数据准确 | 进度同步准确,提现金额正确 | 卡若 | +| 无严重Bug | 不影响核心流程的使用 | 卡若 | +| 代码规范 | 符合现有项目规范,有必要注释 | 卡若 | + +--- + +## 九、开发任务优先级 + +### 第一阶段:交互优化(P0) + +| 序号 | 任务 | 预估工作量 | +|:---|:---|:---| +| 1 | 全局登录组件封装 | 0.5天 | +| 2 | 支付模块重构 | 1天 | +| 3 | 数据实时同步机制 | 0.5天 | +| 4 | 阅读进度同步(前后端) | 1天 | + +### 第二阶段:功能增强(P0-P1) + +| 序号 | 任务 | 预估工作量 | +|:---|:---|:---| +| 5 | 全站搜索(前后端) | 1.5天 | +| 6 | 导航结构调整(5个Tab) | 1天 | +| 7 | 合伙人档案系统(前后端) | 2天 | +| 8 | 自动提现功能(前后端) | 1.5天 | + +### 第三阶段:测试与优化 + +| 序号 | 任务 | 预估工作量 | +|:---|:---|:---| +| 9 | 全流程测试 | 1天 | +| 10 | Bug修复与优化 | 1天 | + +**总计预估**:约11天 + +--- + +## 十、下一步行动 + +1. **确认本方案**:如有调整请反馈 +2. **创建开发分支**:`feature/miniprogram-v2` +3. **按优先级开发**:先完成第一阶段交互优化 +4. **每日更新进度**:更新到项目推进表 + +--- + +**方案版本**:v1.0 +**创建时间**:2026-01-23 +**下次评审**:开发完成后