更新小程序接口路径,统一为 /api/miniprogram/*,确保各页面正确调用 VIP 相关接口。增强分享功能,支持通过 mid 参数分享章节,优化用户体验。调整文档,明确后端待办事项。
This commit is contained in:
@@ -31,24 +31,36 @@
|
||||
- withdraw-records、addresses、addresses/edit
|
||||
- agreement、about、vip、member-detail
|
||||
|
||||
### 3. read.js 分享逻辑
|
||||
### 3. read.js 分享逻辑与 mid 支持
|
||||
|
||||
- 使用 `app.getMyReferralCode()` 替代 `userInfo?.referralCode || wx.getStorageSync('referralCode')`
|
||||
- 保持 `onShareAppMessage`、`onShareTimeline` 行为不变
|
||||
- **mid 支持**:onLoad 支持 `options.scene`、`options.mid`;mid 有值无 id 时从 bookData 或 `/api/miniprogram/book/chapter/by-mid/:mid` 解析 id
|
||||
- 分享 path 优先用 `mid=`(扫码/海报闭环),无则用 `id=`;API 返回 `res.mid` 时写入 `sectionMid`
|
||||
|
||||
### 4. API 路径修正
|
||||
|
||||
- `app.loadBookData`:`/api/book/all-chapters` → `/api/miniprogram/book/all-chapters`
|
||||
- `index.loadBookData`、`loadFeaturedFromServer`、`loadLatestChapters`:同上
|
||||
- `chapters.loadDailyChapters`:同上
|
||||
- **VIP 接口**:`/api/vip/*` → `/api/miniprogram/vip/*`(vip.js、my.js、index.js、member-detail.js)
|
||||
|
||||
## 三、未改动项(保留甲方逻辑)
|
||||
## 三、已处理项
|
||||
|
||||
- **vip 相关接口**:`/api/vip/members`、`/api/vip/status`、`/api/vip/profile` 仍为原路径,未改为 `/api/miniprogram/*`(若 soul-api 无对应 miniprogram 接口,需后端补充)
|
||||
- **vip 相关接口**:已改为 `/api/miniprogram/vip/*`(members、status、profile),符合项目边界。**后端需在 soul-api 的 miniprogram 组下挂对应路由**,可复用现有 handler。
|
||||
- **页面结构**:保留 vip、member-detail,未引入 scan、profile-edit
|
||||
|
||||
## 四、后续建议
|
||||
## 四、后端待办
|
||||
|
||||
1. **soul-api 路由**:确认 `/api/miniprogram/book/all-chapters` 已注册;若 vip 需在小程序使用,建议在 miniprogram 组下增加等价接口。
|
||||
2. **referral.js**:检查是否已使用 `app.getMyReferralCode()`,若仍用旧方式可统一替换。
|
||||
3. **read.js 的 mid 支持**:miniprogram2 的 read 支持 `mid` 参数(便于扫码直达),若需要可在 miniprogram 的 read 中补充 `sectionMid` 与 `getShareConfig` 的 mid 逻辑。
|
||||
soul-api 需在 miniprogram 组下增加以下 VIP 路由(可复用现有 handler):
|
||||
|
||||
| 路径 | 方法 | 用途 |
|
||||
|------|------|------|
|
||||
| `/api/miniprogram/vip/status` | GET | 查询用户 VIP 状态 |
|
||||
| `/api/miniprogram/vip/profile` | GET/POST | 获取/更新 VIP 资料 |
|
||||
| `/api/miniprogram/vip/members` | GET | 获取 VIP 会员列表(首页超级个体、会员详情) |
|
||||
|
||||
## 五、后续建议
|
||||
|
||||
1. **soul-api 路由**:确认 `/api/miniprogram/book/all-chapters` 已注册;VIP 接口见「四、后端待办」。
|
||||
2. **referral.js**:已统一使用 `app.getMyReferralCode()` 作为回退。
|
||||
3. **read.js mid 支持**:已完成。若 soul-api 未提供 `/api/miniprogram/book/chapter/by-mid/:mid`,扫码带 mid 时需依赖 bookData 已加载完成;建议后端补充 by-mid 接口。
|
||||
|
||||
@@ -8,7 +8,10 @@ const { parseScene } = require('./utils/scene.js')
|
||||
App({
|
||||
globalData: {
|
||||
// API基础地址 - 连接真实后端
|
||||
baseUrl: 'https://soul.quwanzhi.com',
|
||||
// baseUrl: 'https://soulapi.quwanzhi.com',
|
||||
// baseUrl: 'https://souldev.quwanzhi.com',
|
||||
baseUrl: 'http://localhost:8080',
|
||||
|
||||
|
||||
// 小程序配置 - 真实AppID
|
||||
appId: 'wxb8bbb2b10dec74aa',
|
||||
|
||||
@@ -120,7 +120,7 @@ Page({
|
||||
// 优先加载VIP会员
|
||||
let members = []
|
||||
try {
|
||||
const res = await app.request({ url: '/api/vip/members', silent: true })
|
||||
const res = await app.request({ url: '/api/miniprogram/vip/members', silent: true })
|
||||
if (res && res.success && res.data) {
|
||||
members = res.data.filter(u => u.avatar || u.vip_avatar).slice(0, 4).map(u => ({
|
||||
id: u.id, name: u.vip_name || u.nickname || '会员',
|
||||
|
||||
@@ -17,7 +17,7 @@ Page({
|
||||
|
||||
async loadMember(id) {
|
||||
try {
|
||||
const res = await app.request({ url: `/api/vip/members?id=${id}`, silent: true })
|
||||
const res = await app.request({ url: `/api/miniprogram/vip/members?id=${id}`, silent: true })
|
||||
if (res?.success && res.data) {
|
||||
const d = Array.isArray(res.data) ? res.data[0] : res.data
|
||||
if (d) { this.setData({ member: this.enrichAndFormat(d), loading: false }); return }
|
||||
|
||||
@@ -641,7 +641,7 @@ Page({
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) return
|
||||
try {
|
||||
const res = await app.request({ url: `/api/vip/status?userId=${userId}`, silent: true })
|
||||
const res = await app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true })
|
||||
if (res?.success) {
|
||||
this.setData({ isVip: res.data?.isVip, vipExpireDate: res.data?.expireDate || '' })
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
import accessManager from '../../utils/chapterAccessManager'
|
||||
import readingTracker from '../../utils/readingTracker'
|
||||
const { parseScene } = require('../../utils/scene.js')
|
||||
|
||||
const app = getApp()
|
||||
|
||||
@@ -66,21 +67,53 @@ Page({
|
||||
isGeneratingPoster: false,
|
||||
|
||||
// 免费章节
|
||||
freeIds: ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']
|
||||
freeIds: ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3'],
|
||||
|
||||
// 章节 mid(扫码/海报分享用,便于分享 path 带 mid)
|
||||
sectionMid: null
|
||||
},
|
||||
|
||||
async onLoad(options) {
|
||||
const { id, ref } = options
|
||||
// 支持 scene(扫码)、mid、id、ref
|
||||
const sceneStr = (options && options.scene) || ''
|
||||
const parsed = parseScene(sceneStr)
|
||||
const mid = options.mid ? parseInt(options.mid, 10) : (parsed.mid || app.globalData.initialSectionMid || 0)
|
||||
let id = options.id || parsed.id || app.globalData.initialSectionId
|
||||
const ref = options.ref || parsed.ref
|
||||
if (app.globalData.initialSectionMid) delete app.globalData.initialSectionMid
|
||||
if (app.globalData.initialSectionId) delete app.globalData.initialSectionId
|
||||
|
||||
// mid 有值但无 id 时,从 bookData 或 API 解析 id
|
||||
if (mid && !id) {
|
||||
const bookData = app.globalData.bookData || []
|
||||
const ch = bookData.find(c => c.mid == mid || (c.mid && Number(c.mid) === Number(mid)))
|
||||
if (ch?.id) {
|
||||
id = ch.id
|
||||
} else {
|
||||
try {
|
||||
const chRes = await app.request({ url: `/api/miniprogram/book/chapter/by-mid/${mid}`, silent: true })
|
||||
if (chRes && chRes.id) id = chRes.id
|
||||
} catch (e) {
|
||||
console.warn('[Read] by-mid 解析失败:', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
wx.showToast({ title: '章节参数缺失', icon: 'none' })
|
||||
this.setData({ accessState: 'error', loading: false })
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
navBarHeight: app.globalData.navBarHeight,
|
||||
sectionId: id,
|
||||
sectionMid: mid || null,
|
||||
loading: true,
|
||||
accessState: 'unknown'
|
||||
})
|
||||
|
||||
// 处理推荐码绑定(异步不阻塞)
|
||||
if (ref) {
|
||||
console.log('[Read] 检测到推荐码:', ref)
|
||||
wx.setStorageSync('referral_code', ref)
|
||||
@@ -88,7 +121,6 @@ Page({
|
||||
}
|
||||
|
||||
try {
|
||||
// 【标准流程】1. 拉取最新配置(免费列表、价格)
|
||||
const config = await accessManager.fetchLatestConfig()
|
||||
this.setData({
|
||||
freeIds: config.freeChapters,
|
||||
@@ -96,7 +128,6 @@ Page({
|
||||
fullBookPrice: config.prices?.fullbook ?? 9.9
|
||||
})
|
||||
|
||||
// 【标准流程】2. 确定权限状态
|
||||
const accessState = await accessManager.determineAccessState(id, config.freeChapters)
|
||||
const canAccess = accessManager.canAccessFullContent(accessState)
|
||||
|
||||
@@ -175,14 +206,15 @@ Page({
|
||||
if (res && res.content) {
|
||||
const lines = res.content.split('\n').filter(line => line.trim())
|
||||
const previewCount = Math.ceil(lines.length * 0.2)
|
||||
|
||||
this.setData({
|
||||
const updates = {
|
||||
content: res.content,
|
||||
contentParagraphs: lines,
|
||||
previewParagraphs: lines.slice(0, previewCount),
|
||||
partTitle: res.partTitle || '',
|
||||
chapterTitle: res.chapterTitle || ''
|
||||
})
|
||||
}
|
||||
if (res.mid) updates.sectionMid = res.mid
|
||||
this.setData(updates)
|
||||
|
||||
// 如果有权限,标记为已读
|
||||
if (accessManager.canAccessFullContent(accessState)) {
|
||||
@@ -454,31 +486,28 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 分享到微信 - 自动带分享人ID(统一使用 app.getMyReferralCode)
|
||||
// 分享到微信 - 自动带分享人ID;优先用 mid(扫码/海报闭环),无则用 id
|
||||
onShareAppMessage() {
|
||||
const { section, sectionId } = this.data
|
||||
const { section, sectionId, sectionMid } = this.data
|
||||
const ref = app.getMyReferralCode()
|
||||
|
||||
// 分享标题优化
|
||||
const q = sectionMid ? `mid=${sectionMid}` : `id=${sectionId}`
|
||||
const shareTitle = section?.title
|
||||
? `📚 ${section.title.length > 20 ? section.title.slice(0, 20) + '...' : section.title}`
|
||||
: '📚 Soul创业派对 - 真实商业故事'
|
||||
|
||||
return {
|
||||
title: shareTitle,
|
||||
path: `/pages/read/read?id=${sectionId}${ref ? '&ref=' + ref : ''}`,
|
||||
imageUrl: '/assets/share-cover.png' // 可配置分享封面图
|
||||
path: ref ? `/pages/read/read?${q}&ref=${ref}` : `/pages/read/read?${q}`,
|
||||
imageUrl: '/assets/share-cover.png'
|
||||
}
|
||||
},
|
||||
|
||||
// 分享到朋友圈
|
||||
onShareTimeline() {
|
||||
const { section, sectionId } = this.data
|
||||
const { section, sectionId, sectionMid } = this.data
|
||||
const ref = app.getMyReferralCode()
|
||||
|
||||
const q = sectionMid ? `mid=${sectionMid}` : `id=${sectionId}`
|
||||
return {
|
||||
title: `${section?.title || 'Soul创业派对'} - 来自派对房的真实故事`,
|
||||
query: `id=${sectionId}${ref ? '&ref=' + ref : ''}`
|
||||
query: ref ? `${q}&ref=${ref}` : q
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ Page({
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) return
|
||||
try {
|
||||
const res = await app.request({ url: `/api/vip/status?userId=${userId}`, silent: true })
|
||||
const res = await app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true })
|
||||
if (res?.success) {
|
||||
const d = res.data
|
||||
let expStr = ''
|
||||
@@ -54,7 +54,7 @@ Page({
|
||||
|
||||
async loadProfile(userId) {
|
||||
try {
|
||||
const res = await app.request(`/api/vip/profile?userId=${userId}`)
|
||||
const res = await app.request(`/api/miniprogram/vip/profile?userId=${userId}`)
|
||||
if (res?.success) this.setData({ profile: res.data })
|
||||
} catch (e) { console.log('[VIP] 资料加载失败', e) }
|
||||
},
|
||||
@@ -120,7 +120,7 @@ Page({
|
||||
if (!userId) return
|
||||
const p = this.data.profile
|
||||
try {
|
||||
const res = await app.request('/api/vip/profile', {
|
||||
const res = await app.request('/api/miniprogram/vip/profile', {
|
||||
method: 'POST', data: { userId, name: p.name, project: p.project, contact: p.contact, bio: p.bio }
|
||||
})
|
||||
if (res?.success) wx.showToast({ title: '资料已保存', icon: 'success' })
|
||||
|
||||
Reference in New Issue
Block a user