# 二期 — 音频内容付费收听系统设计 > 更新时间:2026-05-21 > 目标:用户生成书籍音频专辑后,其它用户通过付费购买进行收听 --- ## 一、业务流程全景 ``` 【创作者 A】 【消费者 B】 │ │ ├─ 创建书籍 + AI 生成音频 ├─ 逛有声集市 ├─ 发布到有声集市 ├─ 试听预览片段 ├─ 设定价格(整张一口价) ├─ 付费购买专辑 ├─ 查看收益、提现 ├─ 解锁全部内容,永久收听 ├─ 我的已购 ``` --- ## 二、数据库设计 ### 2.1 新增模型 ```prisma // 有声集市 - 专辑上架定价 model AlbumMarketListing { id Int @id @default(autoincrement()) bookId Int @unique creatorId Int title String description String? @db.Text coverUrl String? price Decimal @default(0.00) @db.Decimal(10, 2) // 售价(整张一口价) isActive Boolean @default(false) // 是否上架 isRecommended Boolean @default(false) // 推荐位 totalSales Int @default(0) // 累计销量 totalRevenue Float @default(0.00) // 累计销售额 avgRating Float @default(0.00) previewChapterCount Int @default(3) // 免费试听章节数 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt book Book @relation(fields: [bookId], references: [id]) @@index([isActive, totalSales]) @@index([creatorId]) } // 内容购买记录 model ContentPurchase { id Int @id @default(autoincrement()) buyerId Int listingId Int bookId Int orderNo String @unique amount Decimal @db.Decimal(10, 2) // 实付金额 status String @default("success") // 'success' | 'refunded' paymentMethod String? paymentId String? platformFee Decimal @default(0) @db.Decimal(10, 2) creatorShare Decimal @default(0) @db.Decimal(10, 2) platformShare Decimal @default(0) @db.Decimal(10, 2) createdAt DateTime @default(now()) listing AlbumMarketListing @relation(fields: [listingId], references: [id]) buyer User @relation("buyer", fields: [buyerId], references: [id]) @@unique([buyerId, bookId]) // 每人每本书只能购买一次 @@index([buyerId, createdAt]) @@index([listingId]) @@index([orderNo]) } // 创作者收益记录 model CreatorEarning { id Int @id @default(autoincrement()) creatorId Int purchaseId Int bookId Int amount Decimal @db.Decimal(10, 2) // Float→Decimal type String // 'sale' | 'refund' status String @default("pending") // 'pending' | 'settled' | 'withdrawn' settleDate DateTime? withdrawDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt creator User @relation(fields: [creatorId], references: [id]) purchase ContentPurchase @relation(fields: [purchaseId], references: [id]) @@index([creatorId, status]) @@index([creatorId, createdAt]) } // 创作者钱包 model CreatorWallet { id Int @id @default(autoincrement()) userId Int @unique balance Decimal @default(0.00) @db.Decimal(12, 2) // 可提现余额 totalEarned Decimal @default(0.00) @db.Decimal(12, 2) totalWithdrawn Decimal @default(0.00) @db.Decimal(12, 2) frozenBalance Decimal @default(0.00) @db.Decimal(12, 2) // T+7 冻结余额 createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) } // 提现记录 model WithdrawRecord { id Int @id @default(autoincrement()) userId Int amount Decimal @db.Decimal(10, 2) // 提现金额 method String @default("alipay") account String status String @default("pending") remark String? approvedAt DateTime? paidAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([userId, status]) @@index([status, createdAt]) } ``` ### 2.2 现有模型修改 ```prisma // User 新增 model User { // ... 现有字段 ... isCreator Boolean @default(false) creatorBio String? creatorListings AlbumMarketListing[] purchases ContentPurchase[] creatorEarnings CreatorEarning[] creatorWallet CreatorWallet? withdrawRecords WithdrawRecord[] } // Book 新增 model Book { // ... 现有字段 ... totalSales Int @default(0) marketListing AlbumMarketListing? } ``` --- ## 三、API 设计 ### 3.1 有声集市 API (`/api/marketplace`) | 方法 | 路由 | 功能 | |------|------|------| | GET | `/api/marketplace/albums` | 集市列表(分类/排序/分页) | | GET | `/api/marketplace/albums/:id` | 专辑详情(试听控制+购买状态) | | GET | `/api/marketplace/albums/:id/try` | 获取试听章节内容 | | POST | `/api/marketplace/albums/:id/purchase` | 购买专辑 | | GET | `/api/marketplace/purchases` | 我的已购列表 | | GET | `/api/marketplace/check-access/:bookId` | 检查访问权限 | ### 3.2 创作者中心 API (`/api/creator`) | 方法 | 路由 | 功能 | |------|------|------| | POST | `/api/creator/activate` | 激活创作者身份 | | GET | `/api/creator/dashboard` | 仪表盘汇总 | | GET | `/api/creator/listings` | 我的上架作品 | | POST | `/api/creator/listings/:bookId` | 创建/更新上架定价 | | DELETE | `/api/creator/listings/:listingId` | 下架作品 | | GET | `/api/creator/earnings` | 收益明细 | | GET | `/api/creator/wallet` | 钱包信息 | | POST | `/api/creator/withdraw` | 申请提现 | ### 3.3 内容鉴权中间件 ```typescript // 核心逻辑:整张专辑一口价,购买后解锁全部章节 export async function requireContentAccess(ctx, next) { const userId = ctx.state.user?.id; const bookId = Number(ctx.params.bookId); const chapterId = Number(ctx.params.chapterId); // 1. 创作者本人 → 放行 const book = await prisma.book.findUnique({ where: { id: bookId } }); if (book?.userId === userId) return next(); // 2. 已购买整张专辑 → 放行 const purchase = await prisma.contentPurchase.findFirst({ where: { buyerId: userId, bookId, status: 'success' } }); if (purchase) return next(); // 3. 试听章节 → 放行 const listing = await prisma.albumMarketListing.findUnique({ where: { bookId, isActive: true } }); if (listing) { const chapters = await prisma.bookChapter.findMany({ where: { bookId, level: 1 }, orderBy: { number: 'asc' } }); const idx = chapters.findIndex(c => c.id === chapterId); if (idx >= 0 && idx < listing.previewChapterCount) return next(); } // 4. 拒绝 ctx.status = 402; ctx.body = { code: 402, message: '此内容需要购买后才能收听', needPurchase: true, listingId: listing?.id }; } ``` --- ## 四、定价与分账 ### 定价模型 创作者自主定价,**整张专辑一口价**,简单清晰: | 定价档位 | 建议价格 | 适用场景 | |---------|---------|---------| | 体验价 | ¥0.99 ~ ¥4.99 | 短篇/新人引流 | | 标准价 | ¥4.99 ~ ¥19.99 | 中长篇/常规内容 | | 精品价 | ¥19.99 ~ ¥49.99 | 高质量/独家内容 | | 旗舰价 | ¥49.99 ~ ¥99.99 | 超长篇/系列合集 | ### 分账比例 ``` 消费者支付 ¥10 ├─ 1% 支付手续费 → ¥0.10 ├─ 20% 平台技术服务费 → ¥1.98 └─ 79% 创作者分成 → ¥7.92 ``` ### 结算规则 - **结算周期**:T+7(购买后第7天自动结算) - **提现方式**:支付宝 / 微信 - **最低提现**:¥10 - **到账时间**:1-3 个工作日 --- ## 五、前端页面设计 ### 新增页面(7个) | # | 页面路径 | 名称 | 功能 | |---|---------|------|------| | 1 | `pages/marketplace/index` | 有声集市 | 浏览上架专辑,分类/排序/瀑布流 | | 2 | `pages/marketplace/detail` | 专辑购买页 | 详情、试听、价格、购买 | | 3 | `pages/creator/dashboard` | 创作者中心 | 数据仪表盘 | | 4 | `pages/creator/listings` | 作品管理 | 上架/下架/定价 | | 5 | `pages/creator/earnings` | 收益明细 | 流水查看 | | 6 | `pages/creator/wallet` | 我的钱包 | 余额/提现 | | 7 | `pages/purchases/index` | 我的已购 | 已购内容库 | ### 页面流程 ``` 【消费者】 首页 → [有声集市] → 专辑详情 → 试听 → 购买 → 支付 → 解锁 → 播放 └→ [我的已购] 【创作者】 我的 → [创作者中心] → [作品管理] → 选择作品 → 设定价格 → 上架 → [收益明细] → 查看流水 → [我的钱包] → 提现 ``` ### UI 关键页面说明 **有声集市首页**:分类标签栏(全部/有声书/知识/故事)+ 排序(销量/最新/价格)+ 双列瀑布流,每张卡片显示封面、标题、创作者、价格、评分。 **专辑购买页**:大封面 + 标题/创作者/评分/销量 + 章节列表(前3章可试听🎧,后面显示🔒)+ 底部固定购买按钮(显示价格)。 **创作者中心**:头像+名称 + 三指标卡片(累计销量/收益/余额)+ 收益趋势图 + 快捷入口。 --- ## 六、功能开发清单 | ID | 功能 | 优先级 | |----|------|--------| | 1 | 数据库模型扩展 + Prisma 迁移 | 🔴 P0 | | 2 | 有声集市列表 API + 前端页面 | 🔴 P0 | | 3 | 专辑详情 API + 购买页 | 🔴 P0 | | 4 | 购买流程 + 支付对接 | 🔴 P0 | | 5 | 内容鉴权中间件 | 🔴 P0 | | 6 | 我的已购页面 | 🟡 P1 | | 7 | 创作者激活 | 🟡 P1 | | 8 | 作品管理(上架/下架/定价) | 🟢 P2 | | 9 | 创作者仪表盘 | 🟢 P2 | | 10 | 收益明细 + 钱包 + 提现 | 🟢 P2 | | 11 | 首页集市入口 + 推荐卡片 | 🟡 P1 | **预估总工时:约 36 小时(4.5 个工作日)** --- ## 七、关键决策待确认 | # | 决策项 | 建议 | |---|--------|------| | 1 | 分账比例 | 平台 20% / 创作者 79% / 支付费 1% | | 2 | 结算周期 | T+7 | | 3 | 最低提现额 | ¥10 | | 4 | 试听章节数 | 前 3 章 | | 5 | 定价范围 | ¥0.99 ~ ¥99.99(整张一口价) | | 6 | 创作者门槛 | 完成至少 1 本书籍音频生成 | | 7 | 内容审核 | 初期不上审核,后续接入 | --- ## 八、关键原则 - 会员订阅(生成配额)和内容购买(收听权限)**两套独立体系** - 已购内容**永久有效**,不受会员到期影响 - 创作者**始终免费**访问自己的作品 - 复用现有支付网关(支付宝/微信) - 下架不影响已购买用户 --- ## 九、设计评审补充(2026-05-21) > 以下为评审后发现的必须修复项和优化建议。 ### 🔴 必须修复 #### 9.1 金额字段改用 Decimal 所有金额字段从 `Float` 改为 `Decimal`,与现有 `Order.amount` 保持一致,避免浮点精度问题。 ```prisma // 修改前 albumPrice Float @default(0.00) // 修改后 albumPrice Decimal @default(0.00) @db.Decimal(10, 2) ``` **涉及字段**:AlbumMarketListing.price / totalRevenue、ContentPurchase.amount / platformFee / creatorShare / platformShare、CreatorEarning.amount、CreatorWallet.balance / totalEarned / totalWithdrawn / frozenBalance、WithdrawRecord.amount #### 9.2 音频文件防盗链 核心问题:当前 `audioUrl` 是静态路径(如 `/public/videos/xxx.mp3`),购买者拿到 URL 可直接分享。 **方案:签名 URL + 音频代理端点** ``` 改造前:前端直接播放 /public/videos/chapter1.mp3 改造后:前端请求 /api/marketplace/audio/:chapterId?token=xxx 流程: 1. 前端请求音频播放地址 2. 后端验证用户权限(所有者/已购买/试听章节) 3. 生成带签名的临时 URL(有效期 2 小时) 4. 返回签名 URL,前端用签名 URL 播放 5. 过期后需重新请求 ``` ```typescript // 新增 API GET /api/marketplace/audio/:chapterId → 鉴权 → 生成签名 URL → 302 重定向到签名 URL // 签名 URL 格式 /protected/audio/chapter1.mp3?sign=abc123&expires=1716288000 // Nginx 层验证签名 location /protected/audio/ { secure_link $arg_sign; secure_link_md5 "$uri $arg_expires $secret"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } # expired alias /path/to/audio/; } ``` #### 9.3 重复购买防护 ```prisma // ContentPurchase 联合唯一约束 model ContentPurchase { // ... 现有字段 ... @@unique([buyerId, bookId]) // 每人每本书只能购买一次 } ``` 同时购买操作需用数据库事务 + 乐观锁: ```typescript async function purchaseAlbum(buyerId: number, listingId: number) { return await prisma.$transaction(async (tx) => { // 1. 检查是否已购买(防重复) const existing = await tx.contentPurchase.findFirst({ where: { buyerId, bookId: listing.bookId, status: 'success' } }); if (existing) throw new Error('已购买该专辑'); // 2. 创建订单 + 扣款 + 分账(原子操作) // ... }); } ``` #### 9.4 上架前置校验 ```typescript // 上架前必须校验 async function validateBeforeListing(bookId: number) { const book = await prisma.book.findUnique({ where: { id: bookId }, include: { chapters: { where: { level: 1 } } } }); const errors: string[] = []; if (!book) errors.push('书籍不存在'); if (book.progress < 100) errors.push('书籍内容尚未生成完成'); if (book.chapters.length === 0) errors.push('书籍没有任何章节'); // 检查至少有 1 个章节已生成音频 const chaptersWithAudio = book.chapters.filter(c => c.audioUrl); if (chaptersWithAudio.length === 0) errors.push('书籍没有任何音频内容'); // 检查是否已公开 const publicChapters = book.chapters.filter(c => c.isPublic); if (publicChapters.length === 0) errors.push('请先将至少 1 个章节设为公开'); return { valid: errors.length === 0, errors }; } ``` ### 🟡 重要补充 #### 9.5 AlbumMarketListing 新增 category 字段 ```prisma model AlbumMarketListing { // ... 现有字段 ... category String @default("有声书") // '有声书' | '知识' | '故事' | '其他' @@index([isActive, category]) } ``` #### 9.6 评分系统补全 ```prisma // 新增:内容评分模型 model ContentRating { id Int @id @default(autoincrement()) userId Int listingId Int rating Int // 1-5 星 review String? @db.Text // 评价文字 createdAt DateTime @default(now()) listing AlbumMarketListing @relation(fields: [listingId], references: [id]) user User @relation(fields: [userId], references: [id]) @@unique([userId, listingId]) // 每人只能评一次 @@index([listingId]) } ``` 新增 API: ``` POST /api/marketplace/albums/:id/rate → 提交评分(购买后才能评) GET /api/marketplace/albums/:id/reviews → 获取评价列表 ``` #### 9.7 T+7 结算定时任务 ```typescript // server/src/modules/marketplace/settlement.job.ts /** * 每日凌晨执行:扫描购买后超过 7 天的 pending 收益,自动结算 */ export async function settleEarnings() { const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); // 找到所有待结算的收益 const pendingEarnings = await prisma.creatorEarning.findMany({ where: { status: 'pending', createdAt: { lte: sevenDaysAgo } } }); for (const earning of pendingEarnings) { await prisma.$transaction(async (tx) => { // 1. 更新收益状态为 settled await tx.creatorEarning.update({ where: { id: earning.id }, data: { status: 'settled', settleDate: new Date() } }); // 2. 从冻结余额转入可提现余额 await tx.creatorWallet.update({ where: { userId: earning.creatorId }, data: { frozenBalance: { decrement: earning.amount }, balance: { increment: earning.amount }, totalEarned: { increment: earning.amount } } }); }); } console.log(`[Settlement] Settled ${pendingEarnings.length} earnings`); } // 注册为定时任务(node-cron) // cron.schedule('0 2 * * *', settleEarnings); // 每天凌晨 2 点 ``` #### 9.8 内容鉴权中间件(简化版) 只有整张专辑一种购买方式,鉴权逻辑清晰: ```typescript export async function requireContentAccess(ctx, next) { const userId = ctx.state.user?.id; const bookId = Number(ctx.params.bookId); const chapterId = Number(ctx.params.chapterId); // 1. 创作者本人 → 放行 const book = await prisma.book.findUnique({ where: { id: bookId } }); if (book?.userId === userId) return next(); // 2. 已购买 → 放行 const purchase = await prisma.contentPurchase.findFirst({ where: { buyerId: userId, bookId, status: 'success' } }); if (purchase) return next(); // 3. 试听章节 → 放行 const listing = await prisma.albumMarketListing.findUnique({ where: { bookId, isActive: true } }); if (listing) { const chapters = await prisma.bookChapter.findMany({ where: { bookId, level: 1 }, orderBy: { number: 'asc' } }); const idx = chapters.findIndex(c => c.id === chapterId); if (idx >= 0 && idx < listing.previewChapterCount) return next(); } // 4. 拒绝 ctx.status = 402; ctx.body = { code: 402, message: '此内容需要购买后才能收听', needPurchase: true, listingId: listing?.id }; } ``` #### 9.9 专辑更新策略 ``` 策略:已购用户永久享受当前及新增内容 实现: 1. 创作者新增章节后,如专辑已上架,新章节自动加入 2. 已购买用户无需额外付费即可收听新章节 3. 价格调整不影响已购买用户 ``` #### 9.10 提现安全增强 ```typescript // 提现前验证 async function validateWithdrawal(userId: number, amount: number, account: string) { // 1. 验证用户身份(已绑定手机号) const user = await prisma.user.findUnique({ where: { id: userId } }); if (!user?.phone) throw new Error('请先绑定手机号'); // 2. 验证码校验(前端获取验证码后传入) // request.body.verifyCode → 校验短信验证码 // 3. 金额校验 const wallet = await prisma.creatorWallet.findUnique({ where: { userId } }); if (amount > wallet.balance) throw new Error('余额不足'); if (amount < 10) throw new Error('最低提现金额 ¥10'); // 4. 账号校验(支付宝:手机号或邮箱格式;微信:openid) if (method === 'alipay' && !/^(1\d{10}|[\w.]+@\w+\.\w+)$/.test(account)) { throw new Error('支付宝账号格式不正确'); } // 5. 频率限制(每天最多 1 次提现) const todayWithdraw = await prisma.withdrawRecord.count({ where: { userId, createdAt: { gte: new Date(new Date().setHours(0,0,0,0)) } } }); if (todayWithdraw >= 1) throw new Error('每天最多提现 1 次'); } ``` ### 🟢 优化建议 #### 9.11 集市搜索 API ``` GET /api/marketplace/search?q=三体&category=有声书&sort=sales ``` ```prisma // AlbumMarketListing 新增全文索引 model AlbumMarketListing { // ... 现有字段 ... @@index([isActive, category]) // MySQL 全文索引需要在 SQL 层添加 } ``` ```typescript // 搜索逻辑(先用 LIKE,后期可接 Elasticsearch) async function searchMarketplace(keyword: string, category?: string) { return prisma.albumMarketListing.findMany({ where: { isActive: true, ...(category ? { category } : {}), OR: [ { title: { contains: keyword } }, { description: { contains: keyword } }, { book: { title: { contains: keyword } } } ] }, orderBy: { totalSales: 'desc' } }); } ``` #### 9.12 创作者公开主页 ``` GET /api/marketplace/creators/:creatorId → 返回:创作者信息 + 作品列表 + 总销量 + 总评分 ``` 用途:消费者点击创作者头像,进入创作者主页查看所有作品。 #### 9.13 分享传播机制 ``` POST /api/marketplace/albums/:id/share → 生成分享链接 + 海报图片 GET /api/marketplace/share/:shareCode → 解析分享链接,跳转到专辑详情页 追踪:分享来源统计(谁分享的 → 谁通过分享购买 → 分享者奖励) ``` #### 9.14 退款流程 ``` 策略: · 购买后 24 小时内可申请退款 · 已收听超过 50% 内容不可退款 · 退款后立即撤销访问权限 · 退款金额从创作者冻结余额扣除 API: POST /api/marketplace/purchases/:orderNo/refund → 验证条件 → 创建退款 → 撤销权限 → 通知创作者 ``` --- ## 十、修订后的完整数据模型 ```prisma model AlbumMarketListing { id Int @id @default(autoincrement()) bookId Int @unique creatorId Int title String description String? @db.Text coverUrl String? category String @default("有声书") price Decimal @default(0.00) @db.Decimal(10, 2) // 售价(整张一口价) isActive Boolean @default(false) isRecommended Boolean @default(false) totalSales Int @default(0) totalRevenue Decimal @default(0.00) @db.Decimal(12, 2) avgRating Float @default(0.00) previewChapterCount Int @default(3) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt book Book @relation(fields: [bookId], references: [id]) ratings ContentRating[] @@index([isActive, category]) @@index([isActive, totalSales]) @@index([creatorId]) } model ContentPurchase { id Int @id @default(autoincrement()) buyerId Int listingId Int bookId Int orderNo String @unique amount Decimal @db.Decimal(10, 2) status String @default("success") paymentMethod String? paymentId String? platformFee Decimal @default(0) @db.Decimal(10, 2) creatorShare Decimal @default(0) @db.Decimal(10, 2) platformShare Decimal @default(0) @db.Decimal(10, 2) createdAt DateTime @default(now()) listing AlbumMarketListing @relation(fields: [listingId], references: [id]) buyer User @relation("buyer", fields: [buyerId], references: [id]) @@unique([buyerId, bookId]) @@index([buyerId, createdAt]) @@index([listingId]) @@index([orderNo]) } model ContentRating { id Int @id @default(autoincrement()) userId Int listingId Int rating Int // 1-5 review String? @db.Text createdAt DateTime @default(now()) listing AlbumMarketListing @relation(fields: [listingId], references: [id]) user User @relation(fields: [userId], references: [id]) @@unique([userId, listingId]) @@index([listingId]) } model CreatorEarning { id Int @id @default(autoincrement()) creatorId Int purchaseId Int bookId Int amount Decimal @db.Decimal(10, 2) // Float→Decimal type String status String @default("pending") settleDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt creator User @relation(fields: [creatorId], references: [id]) purchase ContentPurchase @relation(fields: [purchaseId], references: [id]) @@index([creatorId, status]) @@index([creatorId, createdAt]) } model CreatorWallet { id Int @id @default(autoincrement()) userId Int @unique balance Decimal @default(0.00) @db.Decimal(12, 2) // Float→Decimal totalEarned Decimal @default(0.00) @db.Decimal(12, 2) totalWithdrawn Decimal @default(0.00) @db.Decimal(12, 2) frozenBalance Decimal @default(0.00) @db.Decimal(12, 2) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) } model WithdrawRecord { id Int @id @default(autoincrement()) userId Int amount Decimal @db.Decimal(10, 2) // Float→Decimal method String @default("alipay") account String status String @default("pending") remark String? approvedAt DateTime? paidAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id]) @@index([userId, status]) @@index([status, createdAt]) } ``` --- ## 十一、修订后的 API 补充 | 方法 | 路由 | 功能 | 来源 | |------|------|------|------| | GET | `/api/marketplace/search` | 集市搜索 | 9.11 | | GET | `/api/marketplace/creators/:id` | 创作者主页 | 9.12 | | GET | `/api/marketplace/audio/:chapterId` | 音频鉴权代理(防盗链) | 9.2 | | POST | `/api/marketplace/albums/:id/rate` | 提交评分 | 9.6 | | GET | `/api/marketplace/albums/:id/reviews` | 评价列表 | 9.6 | | POST | `/api/marketplace/purchases/:orderNo/refund` | 申请退款 | 9.14 | | POST | `/api/marketplace/albums/:id/share` | 生成分享 | 9.13 | --- ## 十二、修订后功能开发清单 | ID | 功能 | 优先级 | 备注 | |----|------|--------|------| | 1 | 数据库模型扩展(含 Decimal 修正) | 🔴 P0 | 评审 9.1 | | 2 | 音频防盗链 — 签名 URL + 代理端点 | 🔴 P0 | 评审 9.2 | | 3 | 有声集市列表 API + 前端 | 🔴 P0 | 含 category 筛选 | | 4 | 专辑详情 API + 购买页 | 🔴 P0 | | | 5 | 购买流程(含防重复 + 事务安全) | 🔴 P0 | 评审 9.3 | | 6 | 内容鉴权中间件 | 🔴 P0 | 评审 9.8 | | 7 | 上架前置校验 | 🔴 P0 | 评审 9.4 | | 8 | 我的已购页面 | 🟡 P1 | | | 9 | 创作者激活 | 🟡 P1 | | | 10 | 作品管理(上架/下架/定价) | 🟡 P1 | | | 11 | T+7 结算定时任务 | 🟡 P1 | 评审 9.7 | | 12 | 集市搜索 API | 🟡 P1 | 评审 9.11 | | 13 | 评分系统 | 🟡 P1 | 评审 9.6 | | 14 | 首页集市入口 | 🟡 P1 | | | 15 | 创作者仪表盘 | 🟢 P2 | | | 16 | 收益明细 + 钱包(含提现安全) | 🟢 P2 | 评审 9.10 | | 17 | 创作者公开主页 | 🟢 P2 | 评审 9.12 | | 18 | 分享传播 | 🟢 P2 | 评审 9.13 | | 19 | 退款流程 | 🟢 P2 | 评审 9.14 | **修订后预估:约 48 小时(6 个工作日)**