1
This commit is contained in:
@@ -11,8 +11,8 @@ const DEFAULT_APP_ID = 'wxb8bbb2b10dec74aa'
|
||||
const DEFAULT_MCH_ID = '1318592501'
|
||||
const DEFAULT_WITHDRAW_TMPL_ID = 'u3MbZGPRkrZIk-I7QdpwzFxnO_CeQPaCWF2FkiIablE'
|
||||
// baseUrl 手动切换(注释方式):
|
||||
const API_BASE_URL = 'http://localhost:8080'
|
||||
// const API_BASE_URL = 'https://soulapi.quwanzhi.com'
|
||||
// const API_BASE_URL = 'http://localhost:9090'
|
||||
const API_BASE_URL = 'https://soulapi.quwanzhi.com'
|
||||
const CONFIG_CACHE_KEY = 'mpConfigCacheV1'
|
||||
// 与上传版本号对齐;设置页展示优先用 wx.getAccountInfoSync().miniProgram.version(正式版),否则用本字段
|
||||
const APP_DISPLAY_VERSION = '1.7.2'
|
||||
|
||||
@@ -46,6 +46,18 @@ const READ_UI_DEFAULTS = {
|
||||
timelineTitleSuffix: '(预览{percent}%)',
|
||||
}
|
||||
|
||||
/** 章节未返回前:用默认比例与价格生成 readUi,避免云端 read_preview_ui 为空时付费墙/预览条不显示 */
|
||||
function buildReadUiFilled(pct, priceTok) {
|
||||
const base = { ...READ_UI_DEFAULTS }
|
||||
const filled = {}
|
||||
Object.keys(base).forEach((k) => {
|
||||
filled[k] = String(base[k] || '')
|
||||
.replace(/\{percent\}/g, String(pct))
|
||||
.replace(/\{price\}/g, String(priceTok))
|
||||
})
|
||||
return filled
|
||||
}
|
||||
|
||||
/** 阅读页解析正文用:人物字典 + #标签(与 /config/read-extras 一致) */
|
||||
function getContentParseConfig() {
|
||||
const g = getApp().globalData || {}
|
||||
@@ -161,11 +173,11 @@ Page({
|
||||
previewPercent: 20,
|
||||
/** 未解锁时:按 previewPercent 裁切可见高度(px)。0 表示未启用/待测量 */
|
||||
previewMaxHeightPx: 0,
|
||||
/** mpUi.readPage.beforeLoginHint:未登录付费墙上方说明文案 */
|
||||
readBeforeLoginHint: '',
|
||||
/** 朋友圈单页:标题与说明(mpUi.readPage.singlePageTitle / singlePagePaywallHint) */
|
||||
readSinglePageTitle: '解锁全文',
|
||||
readSinglePageHint: '',
|
||||
/** 与 mpPagePopups READ_PAGE_FALLBACK 一致;getConfig 前首屏即有字 */
|
||||
readBeforeLoginHint: '试读进度与下方百分比以后台配置为准;登录后可购买解锁全文。',
|
||||
readSinglePageTitle: '解锁完整内容',
|
||||
readSinglePageHint:
|
||||
'当前为朋友圈单页预览,无法在此登录或付款。请点击底部「前往小程序」进入完整版后再解锁本章。',
|
||||
showPaywall: false,
|
||||
|
||||
// 上一篇/下一篇
|
||||
@@ -211,8 +223,8 @@ Page({
|
||||
|
||||
// 未付费预览比例(与后端 unpaid_preview_percent / 章节 preview_percent 一致)
|
||||
effectivePreviewPercent: 20,
|
||||
// 付费墙 / 朋友圈文案(后端 read_preview_ui + 占位符已替换)
|
||||
readUi: {},
|
||||
// 付费墙 / 朋友圈文案(后端 read_preview_ui + 占位符已替换;无云端时用 READ_UI_DEFAULTS)
|
||||
readUi: buildReadUiFilled(20, '1'),
|
||||
},
|
||||
|
||||
_isLockedState(state) {
|
||||
@@ -305,8 +317,16 @@ Page({
|
||||
/** 章节接口 meta:预览比例 + 付费墙/朋友圈文案模板 */
|
||||
_applyChapterMetaFromResponse(res) {
|
||||
if (!res || typeof res !== 'object') return
|
||||
const rawPct =
|
||||
typeof res.unpaidPreviewPercent === 'number'
|
||||
? res.unpaidPreviewPercent
|
||||
: typeof res.unpaid_preview_percent === 'number'
|
||||
? res.unpaid_preview_percent
|
||||
: null
|
||||
const pct =
|
||||
typeof res.unpaidPreviewPercent === 'number' ? res.unpaidPreviewPercent : 20
|
||||
rawPct != null && !isNaN(Number(rawPct))
|
||||
? Math.min(100, Math.max(1, Math.round(Number(rawPct))))
|
||||
: 20
|
||||
const priceNum =
|
||||
res.price != null
|
||||
? Number(res.price)
|
||||
@@ -368,36 +388,30 @@ Page({
|
||||
Promise.all([
|
||||
app.getConfig(),
|
||||
app.getReadExtras()
|
||||
]).then(([cfg, extras]) => {
|
||||
if (cfg) {
|
||||
const mp = (cfg && cfg.mpConfig) || {}
|
||||
const auditMode = !!mp.auditMode
|
||||
app.globalData.auditMode = auditMode
|
||||
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 readSinglePageHint =
|
||||
mpPagePopups.getReadPageContent(app, 'singlePagePaywallHint') ||
|
||||
String((mp.mpUi && mp.mpUi.readPage && mp.mpUi.readPage.singlePagePaywallHint) || '').trim()
|
||||
if (typeof this.setData === 'function') {
|
||||
this.setData({
|
||||
auditMode,
|
||||
readBeforeLoginHint,
|
||||
readSinglePageTitle,
|
||||
readSinglePageHint,
|
||||
})
|
||||
])
|
||||
.then(([cfg, extras]) => {
|
||||
if (cfg) {
|
||||
const mp = (cfg && cfg.mpConfig) || {}
|
||||
const auditMode = !!mp.auditMode
|
||||
app.globalData.auditMode = auditMode
|
||||
if (typeof this.setData === 'function') {
|
||||
this.setData({ auditMode })
|
||||
}
|
||||
}
|
||||
}
|
||||
if (extras && Array.isArray(extras.linkTags)) {
|
||||
app.globalData.linkTagsConfig = extras.linkTags
|
||||
app.globalData.linkedMiniprograms = extras.linkedMiniprograms || []
|
||||
}
|
||||
}).catch(() => {})
|
||||
if (extras && Array.isArray(extras.linkTags)) {
|
||||
app.globalData.linkTagsConfig = extras.linkTags
|
||||
app.globalData.linkedMiniprograms = extras.linkedMiniprograms || []
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
if (typeof this.setData !== 'function') return
|
||||
this.setData({
|
||||
readBeforeLoginHint: mpPagePopups.getReadPageContent(app, 'beforeLoginHint'),
|
||||
readSinglePageTitle: mpPagePopups.getReadPageContent(app, 'singlePageTitle'),
|
||||
readSinglePageHint: mpPagePopups.getReadPageContent(app, 'singlePagePaywallHint'),
|
||||
})
|
||||
})
|
||||
|
||||
// 支持 scene(扫码)、mid、id、ref、gift(代付)
|
||||
const sceneStr = (options && options.scene) || ''
|
||||
@@ -644,6 +658,7 @@ Page({
|
||||
const cached = wx.getStorageSync(cacheKey)
|
||||
if (cached && cached.content) {
|
||||
await app.getReadExtras()
|
||||
this._applyChapterMetaFromResponse(cached)
|
||||
const { lines, segments } = contentParser.parseContent(cached.content, getContentParseConfig())
|
||||
// 预览比例由前端按高度裁切,这里渲染完整内容
|
||||
const previewCount = lines.length
|
||||
@@ -1082,6 +1097,14 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
// 朋友圈/剪贴板文案:控制长度,避免复制过长
|
||||
_formatMomentsClipboardText(text) {
|
||||
const t = String(text || '').trim()
|
||||
const maxLen = 150
|
||||
const truncated = t.length > maxLen ? t.slice(0, maxLen) + '...' : t
|
||||
return `${truncated}\n👉`
|
||||
},
|
||||
|
||||
// 复制链接
|
||||
copyLink() {
|
||||
const userInfo = app.globalData.userInfo
|
||||
@@ -1108,9 +1131,10 @@ Page({
|
||||
推荐给正在创业或想创业的朋友,搜"卡若创业派对"小程序就能看!
|
||||
|
||||
#创业派对 #私域运营 #商业案例`
|
||||
|
||||
|
||||
const copyText = this._formatMomentsClipboardText(shareText)
|
||||
wx.setClipboardData({
|
||||
data: shareText
|
||||
data: copyText
|
||||
// 不额外 showToast:系统已有「内容已复制」,避免与自定义文案叠两层
|
||||
})
|
||||
},
|
||||
@@ -1149,8 +1173,10 @@ Page({
|
||||
const copyText = paras
|
||||
? `${title}\n\n${paras}${footer}`
|
||||
: `${title}${footer || `\n\n—— 预览约 ${this.data.effectivePreviewPercent ?? 20}% ,搜「卡若创业派对」小程序阅读全文 ——`}`
|
||||
|
||||
const clipboardText = this._formatMomentsClipboardText(copyText)
|
||||
wx.setClipboardData({
|
||||
data: copyText,
|
||||
data: clipboardText,
|
||||
success: () => {
|
||||
// 系统会在 setClipboardData 成功后自动 toast「内容已复制」,与下方引导弹窗重复,先关掉再弹窗
|
||||
wx.hideToast()
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
<block wx:if="{{readSinglePageMode}}">
|
||||
<text class="paywall-title">{{readUi.singlePageUnlockTitle || '解锁完整内容'}}</text>
|
||||
<text class="paywall-desc" wx:if="{{readUi.fullUnlockDesc}}">{{readUi.fullUnlockDesc}}</text>
|
||||
<text class="paywall-desc">{{readUi.fullUnlockDesc || '可先上滑阅读预览;需要全文时,点下方「支付¥1」查看说明'}}</text>
|
||||
<view class="purchase-options" wx:if="{{!auditMode}}">
|
||||
<view class="purchase-btn purchase-section purchase-btn--fulltext" bindtap="onUnlockTapInSinglePage">
|
||||
<text class="btn-label btn-label--block">{{readUi.singlePagePayButtonText || '支付解锁'}}</text>
|
||||
@@ -229,7 +229,7 @@
|
||||
|
||||
<block wx:if="{{readSinglePageMode}}">
|
||||
<text class="paywall-title">{{readUi.singlePageUnlockTitle || '解锁完整内容'}}</text>
|
||||
<text class="paywall-desc" wx:if="{{readUi.fullUnlockDesc}}">{{readUi.fullUnlockDesc}}</text>
|
||||
<text class="paywall-desc">{{readUi.fullUnlockDesc || '可先上滑阅读预览;需要全文时,点下方「支付¥1」查看说明'}}</text>
|
||||
<view class="purchase-options" wx:if="{{!auditMode}}">
|
||||
<view class="purchase-btn purchase-section purchase-btn--fulltext" bindtap="onUnlockTapInSinglePage">
|
||||
<text class="btn-label btn-label--block">{{readUi.singlePagePayButtonText || '支付解锁'}}</text>
|
||||
@@ -243,6 +243,7 @@
|
||||
<text class="paywall-title">{{readUi.fullUnlockTitle || '解锁完整内容'}}</text>
|
||||
<text class="paywall-desc">{{readUi.fullUnlockDesc || '可先上滑阅读预览'}}</text>
|
||||
<text class="paywall-subdesc" wx:if="{{readUi.fullLockedProgressText}}">{{readUi.fullLockedProgressText}}</text>
|
||||
<text class="paywall-subdesc" wx:else>已阅读约 {{effectivePreviewPercent}}% ,购买后继续阅读</text>
|
||||
<view class="purchase-options" wx:if="{{!auditMode}}">
|
||||
<view class="purchase-btn purchase-section" bindtap="handlePurchaseSection">
|
||||
<text class="btn-label">购买本章</text>
|
||||
@@ -261,10 +262,6 @@
|
||||
</view>
|
||||
<view class="paywall-audit-tip" wx:if="{{auditMode}}">审核中,暂不支持购买</view>
|
||||
<text class="paywall-tip" wx:if="{{!auditMode}}">{{readUi.fullPaywallTip || '分享给好友一起学习,还能赚取佣金'}}</text>
|
||||
<view class="gift-share-row" bindtap="showGiftShareModal" wx:if="{{isLoggedIn && !auditMode}}">
|
||||
<icon name="gift" size="40" color="#00CED1" customClass="gift-share-icon"></icon>
|
||||
<text class="gift-share-text">代付分享</text>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -812,25 +812,7 @@ button.action-share-native {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
/* ===== 代付分享 ===== */
|
||||
.btn-gift-inline {
|
||||
/* 与 btn-share-inline 同风格 */
|
||||
}
|
||||
.gift-share-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12rpx;
|
||||
margin-top: 24rpx;
|
||||
padding: 20rpx;
|
||||
background: rgba(255, 215, 0, 0.08);
|
||||
border-radius: 24rpx;
|
||||
border: 1rpx solid rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
.gift-share-icon { font-size: 32rpx; }
|
||||
.gift-share-text { font-size: 28rpx; color: #FFD700; }
|
||||
|
||||
/* 代付分享弹窗 */
|
||||
/* ===== 代付分享弹窗 ===== */
|
||||
.gift-modal { padding: 32rpx; }
|
||||
.gift-desc {
|
||||
font-size: 28rpx;
|
||||
|
||||
@@ -610,9 +610,15 @@ Page({
|
||||
// 随机选择一条文案
|
||||
const randomIndex = Math.floor(Math.random() * shareTexts.length)
|
||||
const shareText = shareTexts[randomIndex]
|
||||
|
||||
// 剪贴板文案太长时会影响粘贴体验:截取约150字+省略号,并加👉提示
|
||||
const t = String(shareText || '').trim()
|
||||
const maxLen = 150
|
||||
const truncated = t.length > maxLen ? t.slice(0, maxLen) + '...' : t
|
||||
const clipboardText = `${truncated}\n👉`
|
||||
|
||||
wx.setClipboardData({
|
||||
data: shareText,
|
||||
data: clipboardText,
|
||||
success: () => {
|
||||
wx.showModal({
|
||||
title: '文案已复制',
|
||||
|
||||
@@ -23,6 +23,13 @@
|
||||
"condition": {
|
||||
"miniprogram": {
|
||||
"list": [
|
||||
{
|
||||
"name": "阅读详情",
|
||||
"pathName": "pages/read/read",
|
||||
"query": "mid=233",
|
||||
"scene": null,
|
||||
"launchMode": "default"
|
||||
},
|
||||
{
|
||||
"name": "个人资料",
|
||||
"pathName": "pages/avatar-nickname/avatar-nickname",
|
||||
|
||||
@@ -1,15 +1,51 @@
|
||||
/**
|
||||
* 从 mpConfig.mpUi.pagePopupItems 按 pagePath + key 取文案(管理端 CRUD)。
|
||||
* 兼容旧版 mpUi.memberDetailPage / readPage 字段。
|
||||
* 云端未配置或 content 为空时,使用本文件内写死兜底(与种子文案一致)。
|
||||
*
|
||||
* 当前代码显式引用的键(与 soul-admin 默认种子 / db.defaultMpUi 一致,勿改 key 除非双端同步):
|
||||
* - MEMBER_PATH unlockIntroTitle, unlockIntroBody → member-detail.js _showUnlockIntroThenLogin
|
||||
* - READ_PATH beforeLoginHint, singlePageTitle, singlePagePaywallHint → read.js onLoad
|
||||
* - READ_PATH global* → app.js getGlobalPopupContent(与 pagePopupItems 同页路径存全局键)
|
||||
*/
|
||||
|
||||
const MEMBER_PATH = '/pages/member-detail/member-detail'
|
||||
const READ_PATH = '/pages/read/read'
|
||||
|
||||
/** 阅读页 mpUi 兜底(pagePopupItems / readPage 均无或为空时) */
|
||||
const READ_PAGE_FALLBACK = {
|
||||
beforeLoginHint: '试读进度与下方百分比以后台配置为准;登录后可购买解锁全文。',
|
||||
singlePageTitle: '解锁完整内容',
|
||||
singlePagePaywallHint:
|
||||
'当前为朋友圈单页预览,无法在此登录或付款。请点击底部「前往小程序」进入完整版后再解锁本章。',
|
||||
}
|
||||
|
||||
/** 成员详情解锁说明兜底 */
|
||||
const MEMBER_DETAIL_FALLBACK = {
|
||||
unlockIntroTitle: '解锁与链接说明',
|
||||
unlockIntroBody:
|
||||
'「链接」用于提交留资,由对方通过获客计划跟进;「解锁」用于复制手机/微信号后自行添加好友。\n\n请确认已了解后再登录。',
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局弹窗键与 app.js showModal 兜底一致(pagePath 仍为 READ_PATH,key 以 global 开头)
|
||||
*/
|
||||
const GLOBAL_POPUP_FALLBACK = {
|
||||
globalSinglePageAuthTitle: '请打开完整小程序',
|
||||
globalSinglePageAuthBody:
|
||||
'当前是朋友圈预览,无法在这里登录或付款。请先点击屏幕底部「前往小程序」,进入完整版后再解锁本章。',
|
||||
globalAvatarGuideTitle: '设置头像与昵称',
|
||||
globalAvatarGuideBody: '头像与昵称会出现在名片与匹配卡片上,方便伙伴认出你。',
|
||||
globalVipProfileHintTitle: '补全对外展示信息',
|
||||
globalVipProfileHintBody: 'VIP 名片与派对场景会展示头像与昵称,补全后对方更容易认出你。',
|
||||
globalVipPhoneTitle: '补全手机号',
|
||||
globalVipPhoneBody: '手机号用于找伙伴、提现验证与重要通知,仅本人可见。',
|
||||
globalVipWechatOptionalTitle: '补全微信号(可选)',
|
||||
globalVipWechatOptionalBody: '填写微信号后,对方在允许的场景下能更快加到你;不填也可继续使用。',
|
||||
globalAppUpdateTitle: '更新提示',
|
||||
globalAppUpdateBody: '新版本已准备好,重启后即可使用',
|
||||
}
|
||||
|
||||
function getList(app) {
|
||||
const mpUi = app.globalData.configCache && app.globalData.configCache.mpConfig
|
||||
? app.globalData.configCache.mpConfig.mpUi
|
||||
@@ -42,9 +78,18 @@ function getReadPageContent(app, key) {
|
||||
const rp = (app.globalData.configCache && app.globalData.configCache.mpConfig &&
|
||||
app.globalData.configCache.mpConfig.mpUi &&
|
||||
app.globalData.configCache.mpConfig.mpUi.readPage) || {}
|
||||
if (key === 'beforeLoginHint') return String(rp.beforeLoginHint || '').trim()
|
||||
if (key === 'singlePageTitle') return String(rp.singlePageTitle || '').trim()
|
||||
if (key === 'singlePagePaywallHint') return String(rp.singlePagePaywallHint || '').trim()
|
||||
if (key === 'beforeLoginHint') {
|
||||
const s = String(rp.beforeLoginHint || '').trim()
|
||||
return s || READ_PAGE_FALLBACK.beforeLoginHint
|
||||
}
|
||||
if (key === 'singlePageTitle') {
|
||||
const s = String(rp.singlePageTitle || '').trim()
|
||||
return s || READ_PAGE_FALLBACK.singlePageTitle
|
||||
}
|
||||
if (key === 'singlePagePaywallHint') {
|
||||
const s = String(rp.singlePagePaywallHint || '').trim()
|
||||
return s || READ_PAGE_FALLBACK.singlePagePaywallHint
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -54,15 +99,31 @@ function getMemberDetailContent(app, key) {
|
||||
const md = (app.globalData.configCache && app.globalData.configCache.mpConfig &&
|
||||
app.globalData.configCache.mpConfig.mpUi &&
|
||||
app.globalData.configCache.mpConfig.mpUi.memberDetailPage) || {}
|
||||
if (key === 'unlockIntroTitle') return String(md.unlockIntroTitle || '').trim()
|
||||
if (key === 'unlockIntroBody') return String(md.unlockIntroBody || '').trim()
|
||||
if (key === 'unlockIntroTitle') {
|
||||
const s = String(md.unlockIntroTitle || '').trim()
|
||||
return s || MEMBER_DETAIL_FALLBACK.unlockIntroTitle
|
||||
}
|
||||
if (key === 'unlockIntroBody') {
|
||||
const s = String(md.unlockIntroBody || '').trim()
|
||||
return s || MEMBER_DETAIL_FALLBACK.unlockIntroBody
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局弹窗文案:与阅读页共用 pagePath(后台种子挂在 /pages/read/read),key 为 global* 开头
|
||||
*/
|
||||
function getGlobalPopupContent(app, key) {
|
||||
const v = getPagePopupContent(app, READ_PATH, key)
|
||||
if (v) return v
|
||||
return GLOBAL_POPUP_FALLBACK[key] || ''
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPagePopupContent,
|
||||
getReadPageContent,
|
||||
getMemberDetailContent,
|
||||
getGlobalPopupContent,
|
||||
MEMBER_PATH,
|
||||
READ_PATH,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user