================================================================================ miniprogram/pages/read 阅读页 - 当前处理流程 (ASCII) ================================================================================ ---------- 1. 进入页面 onLoad(options) 总览 ---------- +------------------+ | onLoad(options) | +--------+---------+ | v +----------------------------------------+ | sceneStr = options.scene || '' | | parsed = parseScene(sceneStr) | <-- utils/scene.js | mid = options.mid || parsed.mid || | | app.globalData.initialSectionMid| | id = options.id || parsed.id || | | app.globalData.initialSectionId | | ref = options.ref || parsed.ref | +--------+-------------------------------+ | v +----------------------------------------+ | 清除 app.globalData.initialSection* | +--------+-------------------------------+ | v [ mid || id ? ] | No ---+---> 提示「章节参数缺失」, return | Yes v +----------------------------------------+ | setData: sectionMid, loading=true | | if (ref): 存 referral_code, | | app.handleReferralCode(ref) | +--------+-------------------------------+ | v +----------------------------------------+ | Promise.all: | | - accessManager.fetchLatestConfig() | | - /api/.../purchase-status (若登录) | +--------+-------------------------------+ | v +----------------------------------------+ | 计算价格/推荐折扣, setData 配置 | +--------+-------------------------------+ | v +----------------------------------------+ | resolvedId = id | | if (mid && !id): | | GET /book/chapter/by-mid/:mid | | resolvedId = chRes.id | | prefetchedChapter = chRes | | setData(sectionId: resolvedId) | +--------+-------------------------------+ | v +----------------------------------------+ | accessManager.determineAccessState() | | setData: accessState, canAccess, | | showPaywall, isLoggedIn | +--------+-------------------------------+ | v +----------------------------------------+ | await loadContent(mid, resolvedId, | | accessState, | | prefetchedChapter) | +--------+-------------------------------+ | v +----------------------------------------+ | if (canAccess): readingTracker.init() | | loadNavigation(resolvedId) | | setData(loading: false) | +----------------------------------------+ ---------- 2. scene 闭环(海报生成 <-> 扫码解析)---------- [ 生成海报 ] | v +----------------------------------------+ | buildScene({ mid?, id?, ref? }) | utils/scene.js | 例: mid=1, ref=ogpTW5fmXR | | => "mid=1_ref=ogpTW5fmXR" | +--------+-------------------------------+ | v +----------------------------------------+ | GET /api/miniprogram/qrcode/image | | ?scene=mid%3D1_ref%3Dxxx | | &page=pages/read/read&width=280 | +--------+-------------------------------+ | v +----------------------------------------+ | 后端: & -> _ (若需要), 调微信生成图 | | 返回 image/png | +--------+-------------------------------+ | v +----------------------------------------+ | wx.downloadFile(url) -> tempFilePath | | canvas drawImage(tempFilePath) 画海报 | +----------------------------------------+ ---------- 用户扫码 ---------- +----------------------------------------+ | 微信: 打开 pages/read/read | | options.scene = "mid=1_ref=xxx" | +--------+-------------------------------+ | v +----------------------------------------+ | App.onLaunch(options) | | handleReferralCode(options) | | parseScene(options.scene) | | -> initialSectionMid, initialSectionId| | -> ref 存 referral_code / 绑定 | +----------------------------------------+ | v +----------------------------------------+ | Read.onLoad(options) | | parseScene(options.scene) -> mid,id,ref| | 与 app.globalData.initial* 合并 | | -> 用 mid/id 拉章节, ref 已存 | +----------------------------------------+ ---------- 3. loadContent(mid, id, accessState, prefetched) ---------- +------------------+ | loadContent(...) | +--------+---------+ | v +----------------------------------------+ | section = getSectionInfo(id) | | setData({ section }) | +--------+-------------------------------+ | v +----------------------------------------+ | prefetched 有内容? | +--------+-------------------------------+ | Yes +-----> res = prefetched (不请求) | | No v +----------------------------------------+ | mid ? GET /book/chapter/by-mid/:mid | | : GET /book/chapter/:id | +--------+-------------------------------+ | v +----------------------------------------+ | res && res.content ? | +--------+-------------------------------+ | Yes +-----> setData(content, paragraphs, partTitle, chapterTitle) | if (canAccess): markSectionAsRead(id) | setTimeout(drawShareCard, 600) | | No / 请求异常 v +----------------------------------------+ | 尝试 wx.getStorageSync(cacheKey) | | 有缓存 -> setData 内容; 无 -> throw | +----------------------------------------+ ---------- 4. 参数来源优先级(onLoad 内 mid / id / ref)---------- mid = options.mid ?? parseInt(parsed.mid) ?? app.globalData.initialSectionMid ?? 0 id = options.id ?? parsed.id ?? app.globalData.initialSectionId ?? '' ref = options.ref ?? parsed.ref ?? '' (解析 parsed = parseScene(options.scene),支持 scene 内 & 或 _ 分隔) ================================================================================