From d3353e59c00951293a9209535b7cd17ded9d52df Mon Sep 17 00:00:00 2001 From: Alex-larget <33240357+Alex-larget@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:23:02 +0800 Subject: [PATCH] 1 --- miniprogram/pages/read/read.js | 79 +++++---- miniprogram/pages/read/read.wxml | 108 +++++++------ miniprogram/pages/read/read.wxss | 80 ++++----- miniprogram/project.private.config.json | 23 ++- miniprogram/utils/mpPagePopups.js | 16 +- .../src/pages/settings/mpUiCopyConfig.ts | 152 +++--------------- soul-api/internal/handler/book.go | 5 +- soul-api/internal/handler/db.go | 23 +-- soul-api/internal/model/chapter.go | 2 +- soul-api/wechat/info.log | 16 ++ 10 files changed, 223 insertions(+), 281 deletions(-) diff --git a/miniprogram/pages/read/read.js b/miniprogram/pages/read/read.js index ba86a82a..ad907f18 100644 --- a/miniprogram/pages/read/read.js +++ b/miniprogram/pages/read/read.js @@ -22,6 +22,7 @@ const { checkAndExecute } = require('../../utils/ruleEngine') const soulBridge = require('../../utils/soulBridge.js') const app = getApp() +const mpPagePopups = require('../../utils/mpPagePopups.js') /** 阅读页解析正文用:人物字典 + #标签(与 /config/read-extras 一致) */ function getContentParseConfig() { @@ -47,7 +48,7 @@ function chapterApiContent(res) { } /** 补全 mentionDisplay,避免旧数据无字段;昵称去空白防「@ 名」 */ -/** 试读比例:data.previewPercent;兼容旧响应顶层 previewPercent;缺省 20 */ +/** 试读比例:data.previewPercent(有效试读%);兼容旧响应顶层 previewPercent;缺省 20 */ function normalizePreviewPercent(res) { if (!res) return 20 const tryNum = (v) => { @@ -147,9 +148,11 @@ Page({ previewMaxHeightPx: 0, /** mpUi.readPage.beforeLoginHint:未登录付费墙上方说明文案 */ readBeforeLoginHint: '', - /** 朋友圈单页:标题与说明(mpUi.readPage.singlePageTitle / singlePagePaywallHint) */ - readSinglePageTitle: '解锁全文', - readSinglePageHint: '', + /** 单页长文案:title + sub + 分销(pagePopupItems,key 沿用 singlePage*) */ + readSinglePageTitle: '解锁完整内容', + readSinglePagePaywallSub: '预览页不能直接付款,务必先点底栏「前往小程序」。', + readSinglePageShareLine1: '好友经你分享购买,你可获得约 90% 收益', + readSinglePageShareLine2: '转发给需要的人,一起学习还能赚佣金', showPaywall: false, // 上一篇/下一篇 @@ -199,8 +202,9 @@ Page({ }, /** - * 未解锁时:先渲染完整正文,再测量其高度,按 previewPercent 计算可见高度并裁切。 - * 这样后端无需截断,避免 HTML/段落被截断导致的渲染失败。 + * 未解锁试读:先不设 max-height(previewMaxHeightPx=0),让正文与图片在 DOM 里完整排版; + * 再量 #previewContentMeasure 总高度,按 previewPercent 换算 max-height + overflow:hidden。 + * 图片 widthFix 异步增高后由 onPreviewContentImageLoad 防抖再次测量。 */ _updatePreviewClipHeight() { const state = this.data.accessState @@ -241,6 +245,16 @@ Page({ apply().catch(() => {}) }, + /** 预览区内图片加载完成:布局高度变化,防抖后重新按完整高度裁切 */ + onPreviewContentImageLoad() { + if (!this._isLockedState(this.data.accessState)) return + if (this._previewClipImgTimer) clearTimeout(this._previewClipImgTimer) + this._previewClipImgTimer = setTimeout(() => { + this._previewClipImgTimer = null + this._updatePreviewClipHeight() + }, 200) + }, + /** * 是否处于朋友圈等「单页预览」环境。 * 兼容:部分机型/基础库首帧 getSystemInfoSync().mode 未就绪,需结合 launch/enter scene 1154、getWindowInfo。 @@ -274,7 +288,7 @@ Page({ return !!app.globalData.isSinglePageMode }, - /** 单页模式下点「购买本章」:触觉反馈 + 展开极简说明;引导靠页内文案 + 底栏箭头,不再弹长 Modal */ + /** 单页模式下点「支付解锁」行:触觉反馈;文案与底栏箭头默认已展开,不再弹长 Modal */ onUnlockTapInSinglePage() { trackClick('read', 'btn_click', '单页_解锁引导') try { @@ -290,7 +304,7 @@ Page({ this.setData({ auditMode: app.globalData.auditMode || false, readSinglePageMode: sp, - ...(sp ? {} : { momentsPaywallExpanded: false }), + ...(sp ? { momentsPaywallExpanded: true } : { momentsPaywallExpanded: false }), }) }, @@ -306,16 +320,31 @@ Page({ const mp = (cfg && cfg.mpConfig) || {} const auditMode = !!mp.auditMode app.globalData.auditMode = auditMode - const rp = (mp.mpUi && mp.mpUi.readPage) || {} - const readBeforeLoginHint = String(rp.beforeLoginHint || '').trim() - const readSinglePageTitle = String(rp.singlePageTitle || '解锁全文').trim() || '解锁全文' - const readSinglePageHint = String(rp.singlePagePaywallHint || '').trim() + const readBeforeLoginHint = + mpPagePopups.getReadPageContent(app, 'beforeLoginHint') || + String((mp.mpUi && mp.mpUi.readPage && mp.mpUi.readPage.beforeLoginHint) || '').trim() + let readSinglePageTitle = + mpPagePopups.getReadPageContent(app, 'singlePageTitle') || + String((mp.mpUi && mp.mpUi.readPage && mp.mpUi.readPage.singlePageTitle) || '').trim() || + '解锁完整内容' + readSinglePageTitle = readSinglePageTitle || '解锁完整内容' + const readSinglePagePaywallSub = + mpPagePopups.getReadPageContent(app, 'singlePagePaywallSub') || + '预览页不能直接付款,务必先点底栏「前往小程序」。' + const readSinglePageShareLine1 = + mpPagePopups.getReadPageContent(app, 'singlePageShareEarn1') || + '好友经你分享购买,你可获得约 90% 收益' + const readSinglePageShareLine2 = + mpPagePopups.getReadPageContent(app, 'singlePageShareEarn2') || + '转发给需要的人,一起学习还能赚佣金' if (typeof this.setData === 'function') { this.setData({ auditMode, readBeforeLoginHint, readSinglePageTitle, - readSinglePageHint, + readSinglePagePaywallSub, + readSinglePageShareLine1, + readSinglePageShareLine2, }) } } @@ -358,6 +387,7 @@ Page({ return } + const spMode = this._detectReadSinglePage() this.setData({ statusBarHeight: app.globalData.statusBarHeight, navBarHeight: app.globalData.navBarHeight, @@ -366,8 +396,8 @@ Page({ loading: true, accessState: 'unknown', pendingGiftRequestSn: giftRequestSn || '', - readSinglePageMode: this._detectReadSinglePage(), - momentsPaywallExpanded: false, + readSinglePageMode: spMode, + momentsPaywallExpanded: spMode, }) if (ref) { @@ -555,7 +585,6 @@ Page({ // 先关闭裁切,等 DOM 更新后再测量并按比例裁切 this.setData({ ...updates, previewMaxHeightPx: 0 }) this._updatePreviewClipHeight() - // 写入本地缓存(存 displayContent,供离线/重试降级使用) try { wx.setStorageSync(cacheKey, { ...res }) } catch (_) {} if (accessManager.canAccessFullContent(accessState)) { app.markSectionAsRead(id) @@ -838,7 +867,7 @@ Page({ wx.showToast({ title: '暂无跳转地址', icon: 'none' }) }, - // 点击正文图片 → 全屏预览 + // 点击正文图片 → 全屏预览(预览区图片同时 bindload 触发 onPreviewContentImageLoad) onImageTap(e) { const src = e.currentTarget.dataset.src if (!src) return @@ -1084,12 +1113,8 @@ Page({ setTimeout(() => { wx.hideToast() wx.showModal({ - title: - mpPagePopups.getReadPageContent(app, 'readMomentsShareGuideTitle') || - '分享到朋友圈', - content: - mpPagePopups.getReadPageContent(app, 'readMomentsShareGuideBody') || - '已复制发圈文案(非分享给好友)。\n\n请点击右上角「···」→「分享到朋友圈」粘贴发布。', + title: '分享到朋友圈', + content: '已复制发圈文案(非分享给好友)。\n\n请点击右上角「···」→「分享到朋友圈」粘贴发布。', showCancel: false, confirmText: '知道了' }) @@ -1265,12 +1290,8 @@ Page({ if (needProfile) { const res = await new Promise(resolve => { wx.showModal({ - title: - mpPagePopups.getReadPageContent(app, 'beforePayAvatarNicknameTitle') || - '设置头像与昵称', - content: - mpPagePopups.getReadPageContent(app, 'beforePayAvatarNicknameBody') || - '支付订单会关联你的对外展示信息,请先设置头像与昵称,避免账单与对方看到默认占位。', + title: '设置头像与昵称', + content: '支付订单会关联你的对外展示信息,请先设置头像与昵称,避免账单与对方看到默认占位。', confirmText: '去设置', cancelText: '关闭', success: resolve diff --git a/miniprogram/pages/read/read.wxml b/miniprogram/pages/read/read.wxml index 085e6511..18040637 100644 --- a/miniprogram/pages/read/read.wxml +++ b/miniprogram/pages/read/read.wxml @@ -1,6 +1,6 @@ - + @@ -124,7 +124,7 @@ {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}} - + @@ -132,37 +132,44 @@ - + + {{readSinglePageTitle}} - 试读 {{previewPercent}}%(与后台试读比例一致) - + 全文 ¥{{section && section.price != null ? section.price : sectionPrice}}。预览里无法完成支付:请先点屏幕底部「前往小程序」进入完整版,登录后再付款解锁。 + - 购买本章 - ¥1 + 支付 ¥{{section && section.price != null ? section.price : sectionPrice}} 解锁全文 + ¥{{section && section.price != null ? section.price : sectionPrice}} 审核中,暂不支持购买 - {{readSinglePageHint || '预览不可付款,请点底部「前往小程序」。'}} + {{readSinglePagePaywallSub}} + 解锁完整内容 - {{readBeforeLoginHint}} - 已阅读{{previewPercent}}%,登录并支付 ¥{{section && section.price != null ? section.price : sectionPrice}} 后阅读全文 - - - 购买本章 - ¥{{section && section.price != null ? section.price : sectionPrice}} + {{readBeforeLoginHint}} + + 可先上滑阅读预览;需要全文时,点下方「支付 ¥{{section && section.price != null ? section.price : sectionPrice}}」查看说明 + + + 支付 ¥{{section && section.price != null ? section.price : sectionPrice}} 解锁全文 + ¥{{section && section.price != null ? section.price : sectionPrice}} + - - - 分享给好友一起学习,还能赚取佣金 + + + 审核中,暂不支持购买 @@ -208,7 +215,7 @@ {{seg.text}}{{seg.mentionDisplay}}#{{seg.label}} - + @@ -222,42 +229,47 @@ {{readSinglePageTitle}} - 试读 {{previewPercent}}%(与后台试读比例一致) - + 全文 ¥{{section && section.price != null ? section.price : sectionPrice}}。预览里无法完成支付:请先点屏幕底部「前往小程序」进入完整版,登录后再付款解锁。 + - 购买本章 - ¥1 + 支付 ¥{{section && section.price != null ? section.price : sectionPrice}} 解锁全文 + ¥{{section && section.price != null ? section.price : sectionPrice}} 审核中,暂不支持购买 - {{readSinglePageHint || '预览不可付款,请点底部「前往小程序」。'}} + {{readSinglePagePaywallSub}} + 解锁完整内容 - 已阅读{{previewPercent}}%,购买后继续阅读 - - - 购买本章 - ¥{{section && section.price != null ? section.price : sectionPrice}} - - - - - 解锁全部 {{totalSections}} 章 + + 可先上滑阅读预览;需要全文时,点下方「支付 ¥{{section && section.price != null ? section.price : sectionPrice}}」查看说明 + + + 支付 ¥{{section && section.price != null ? section.price : sectionPrice}} 解锁全文 + ¥{{section && section.price != null ? section.price : sectionPrice}} - - ¥{{fullBookPrice}} - 省82% + + + + 解锁全部 {{totalSections}} 章 + + + ¥{{fullBookPrice}} + 省82% + - + + + 代付分享 + + 审核中,暂不支持购买 - 分享给好友一起学习,还能赚取佣金 - - - 代付分享 - @@ -401,11 +413,9 @@ - -