同步
This commit is contained in:
@@ -19,7 +19,7 @@ Page({
|
||||
},
|
||||
bookInfo: {
|
||||
title: '一场Soul的创业实验',
|
||||
totalChapters: 62,
|
||||
totalChapters: 0, // 来自 book/stats 或 app.getTotalSections()
|
||||
parts: [
|
||||
{ name: '真实的人', chapters: 10 },
|
||||
{ name: '真实的行业', chapters: 15 },
|
||||
@@ -34,7 +34,8 @@ Page({
|
||||
onLoad() {
|
||||
wx.showShareMenu({ withShareTimeline: true })
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
'bookInfo.totalChapters': app.getTotalSections()
|
||||
})
|
||||
this.loadAuthor()
|
||||
this.loadBookStats()
|
||||
@@ -59,7 +60,7 @@ Page({
|
||||
title: d.title || '',
|
||||
bio: d.bio || '',
|
||||
stats: Array.isArray(d.stats) ? d.stats : [
|
||||
{ label: '商业案例', value: '62' },
|
||||
{ label: '商业案例', value: String(app.getTotalSections()) },
|
||||
{ label: '连续直播', value: '365天' },
|
||||
{ label: '派对分享', value: '1000+' }
|
||||
],
|
||||
@@ -81,7 +82,7 @@ Page({
|
||||
try {
|
||||
const res = await app.request({ url: '/api/miniprogram/book/stats', silent: true })
|
||||
if (res?.success && res.data) {
|
||||
const total = res.data?.totalChapters || 62
|
||||
const total = res.data?.totalChapters ?? app.getTotalSections()
|
||||
this.setData({ 'bookInfo.totalChapters': total })
|
||||
const stats = this.data.author?.stats || []
|
||||
const idx = stats.findIndex((s) => s && (s.label === '商业案例' || s.label === '章节'))
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* 改造后:发起人支付,好友领取。支持单页模式引导、登录检测。
|
||||
*/
|
||||
const app = getApp()
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -180,28 +181,10 @@ Page({
|
||||
}
|
||||
const payParams = res.data.payParams
|
||||
const orderSn = res.data.orderSn
|
||||
// 与正常章节支付一致:只传 5 个必需参数,不传 appId 等多余字段
|
||||
await new Promise((resolve, reject) => {
|
||||
wx.requestPayment({
|
||||
timeStamp: payParams.timeStamp,
|
||||
nonceStr: payParams.nonceStr,
|
||||
package: payParams.package,
|
||||
signType: payParams.signType || 'RSA',
|
||||
paySign: payParams.paySign,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
await soulBridge.requestWxJsapiPayment(payParams)
|
||||
wx.showToast({ title: '支付成功', icon: 'success' })
|
||||
this.setData({ paying: false })
|
||||
// 主动同步订单状态(与 read 页一致)
|
||||
if (orderSn) {
|
||||
try {
|
||||
await app.request(`/api/miniprogram/pay?orderSn=${encodeURIComponent(orderSn)}`, { silent: true })
|
||||
} catch (e) {
|
||||
console.warn('[GiftPay] 主动同步订单失败:', e)
|
||||
}
|
||||
}
|
||||
await soulBridge.syncOrderStatusQuery(app, orderSn)
|
||||
this.loadDetail()
|
||||
} catch (e) {
|
||||
this.setData({ paying: false })
|
||||
|
||||
@@ -33,16 +33,12 @@ Page({
|
||||
hasFullBook: false,
|
||||
readCount: 0,
|
||||
|
||||
// 书籍数据
|
||||
totalSections: 62,
|
||||
// 书籍数据(totalSections 来自 book/parts,初始用 app.getTotalSections() 兜底)
|
||||
totalSections: 0, // onLoad 后由 loadBookData 更新
|
||||
bookData: [],
|
||||
|
||||
// 推荐章节
|
||||
featuredSections: [
|
||||
{ id: '1.1', title: '荷包:电动车出租的被动收入模式', tag: '免费', tagClass: 'tag-free', part: '真实的人' },
|
||||
{ id: '3.1', title: '3000万流水如何跑出来', tag: '热门', tagClass: 'tag-pink', part: '真实的行业' },
|
||||
{ id: '8.1', title: '流量杠杆:抖音、Soul、飞书', tag: '推荐', tagClass: 'tag-purple', part: '真实的赚钱' }
|
||||
],
|
||||
// 推荐章节(来自 recommended/hot API,初始为空避免占位错误)
|
||||
featuredSections: [],
|
||||
|
||||
// Banner 推荐(优先用 recommended API 第一条,回退 latest-chapters)
|
||||
bannerSection: null,
|
||||
@@ -277,21 +273,21 @@ Page({
|
||||
if (res?.success) {
|
||||
const total = res.totalSections ?? 0
|
||||
const parts = res.parts || []
|
||||
app.globalData.totalSections = total || 62
|
||||
app.globalData.totalSections = (total != null && total > 0) ? total : app.getTotalSections()
|
||||
this.setData({
|
||||
totalSections: app.globalData.totalSections,
|
||||
partCount: parts.length || 5
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
this.setData({ totalSections: app.globalData.totalSections || 62, partCount: 5 })
|
||||
this.setData({ totalSections: app.getTotalSections(), partCount: 5 })
|
||||
}
|
||||
},
|
||||
|
||||
// 更新用户状态(已读数 = 用户实际打开过的章节数,仅统计有权限阅读的)
|
||||
updateUserStatus() {
|
||||
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
|
||||
const readCount = Math.min(app.getReadCount(), this.data.totalSections || 62)
|
||||
const readCount = Math.min(app.getReadCount(), this.data.totalSections || app.getTotalSections())
|
||||
this.setData({
|
||||
isLoggedIn,
|
||||
hasFullBook,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
const { checkAndExecute } = require('../../utils/ruleEngine.js')
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
|
||||
@@ -426,6 +427,7 @@ Page({
|
||||
|
||||
// 从数据库获取真实用户匹配
|
||||
let matchedUser = null
|
||||
let matchProfileError = ''
|
||||
try {
|
||||
const res = await app.request({ url: '/api/miniprogram/match/users', silent: true,
|
||||
method: 'POST',
|
||||
@@ -434,20 +436,38 @@ Page({
|
||||
userId: app.globalData.userInfo?.id || ''
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if (res.success && res.data) {
|
||||
matchedUser = res.data
|
||||
console.log('[Match] 从数据库匹配到用户:', matchedUser.nickname)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Match] 数据库匹配失败:', e)
|
||||
const r = e.response || {}
|
||||
if (r.errorCode === 'ERR_PROFILE_INCOMPLETE') {
|
||||
matchProfileError = r.message || '请先完善手机号或微信号后再发起匹配'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 延迟显示结果(模拟匹配过程)
|
||||
const delay = Math.random() * 2000 + 2000
|
||||
setTimeout(() => {
|
||||
clearInterval(timer)
|
||||
|
||||
|
||||
if (matchProfileError) {
|
||||
this.setData({ isMatching: false })
|
||||
wx.showModal({
|
||||
title: '完善资料',
|
||||
content: matchProfileError,
|
||||
confirmText: '去完善',
|
||||
showCancel: false,
|
||||
success: (mr) => {
|
||||
if (mr.confirm) wx.navigateTo({ url: '/pages/profile-edit/profile-edit' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果没有匹配到用户,提示用户
|
||||
if (!matchedUser) {
|
||||
this.setData({ isMatching: false })
|
||||
@@ -632,7 +652,27 @@ Page({
|
||||
wx.showToast({ title: res.error || '加入失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '网络异常,请重试', icon: 'none' })
|
||||
const r = e.response || {}
|
||||
if (r.errorCode === 'ERR_REQUIRE_PURCHASE') {
|
||||
wx.showModal({
|
||||
title: '需要先购买',
|
||||
content: r.message || '请先购买章节或解锁全书后再使用资源对接',
|
||||
confirmText: '去购买',
|
||||
cancelText: '取消',
|
||||
success: (mr) => { if (mr.confirm) this.goToChapters() }
|
||||
})
|
||||
} else if (r.errorCode === 'ERR_PROFILE_INCOMPLETE') {
|
||||
wx.showModal({
|
||||
title: '完善资料',
|
||||
content: r.message || '请先完善资料',
|
||||
confirmText: '去完善',
|
||||
success: (mr) => {
|
||||
if (mr.confirm) wx.navigateTo({ url: '/pages/profile-edit/profile-edit' })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: e.message || '网络异常,请重试', icon: 'none' })
|
||||
}
|
||||
} finally {
|
||||
this.setData({ isJoining: false })
|
||||
}
|
||||
@@ -670,9 +710,7 @@ Page({
|
||||
return
|
||||
}
|
||||
|
||||
// 邀请码:与章节支付一致,写入订单便于分销归属与对账
|
||||
const referralCode = wx.getStorageSync('referral_code') || ''
|
||||
// 调用支付接口购买匹配次数
|
||||
const referralCode = soulBridge.getReferralCodeForPay(app)
|
||||
const res = await app.request('/api/miniprogram/pay', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
@@ -685,17 +723,11 @@ Page({
|
||||
referralCode: referralCode || undefined
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if (res.success && res.data?.payParams) {
|
||||
// 调用微信支付
|
||||
await new Promise((resolve, reject) => {
|
||||
wx.requestPayment({
|
||||
...res.data.payParams,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
|
||||
await soulBridge.requestWxJsapiPayment(res.data.payParams)
|
||||
await soulBridge.syncOrderStatusQuery(app, res.data.orderSn)
|
||||
|
||||
// 支付成功,增加匹配次数
|
||||
const extraMatches = (wx.getStorageSync('extra_match_count') || 0) + 1
|
||||
wx.setStorageSync('extra_match_count', extraMatches)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* 点头像:若后台 persons.user_id 已绑定则带 ckbLeadToken,走存客宝 CKBLead(与阅读页 @ 一致)
|
||||
*/
|
||||
const app = getApp()
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
|
||||
Page({
|
||||
data: { statusBarHeight: 44, navBarTotalPx: 88, member: null, loading: true },
|
||||
@@ -188,66 +189,14 @@ Page({
|
||||
wx.showToast({ title: '暂未公开联系方式', icon: 'none' })
|
||||
},
|
||||
|
||||
/** 与 read 页 _doMentionAddFriend 一致:targetUserId = Person.token */
|
||||
/** 与阅读页 @mention 同链路:soulBridge.submitCkbLead */
|
||||
async _doCkbLeadSubmit(targetUserId, targetNickname) {
|
||||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录后再添加好友',
|
||||
confirmText: '去登录',
|
||||
cancelText: '取消',
|
||||
success: (res) => { if (res.confirm) wx.switchTab({ url: '/pages/my/my' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
const myUserId = app.globalData.userInfo.id
|
||||
let phone = (app.globalData.userInfo.phone || wx.getStorageSync('user_phone') || '').trim().replace(/\s/g, '')
|
||||
let wechatId = (app.globalData.userInfo.wechatId || app.globalData.userInfo.wechat_id || wx.getStorageSync('user_wechat') || '').trim()
|
||||
if (!phone || !/^1[3-9]\d{9}$/.test(phone)) {
|
||||
try {
|
||||
const profileRes = await app.request({ url: `/api/miniprogram/user/profile?userId=${myUserId}`, silent: true })
|
||||
if (profileRes?.success && profileRes.data) {
|
||||
phone = (profileRes.data.phone || wx.getStorageSync('user_phone') || '').trim().replace(/\s/g, '')
|
||||
wechatId = (profileRes.data.wechatId || profileRes.data.wechat_id || wx.getStorageSync('user_wechat') || '').trim()
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!phone || !/^1[3-9]\d{9}$/.test(phone)) {
|
||||
wx.showModal({
|
||||
title: '完善资料',
|
||||
content: '请先填写手机号(必填),以便对方通过获客计划联系您',
|
||||
confirmText: '去填写',
|
||||
cancelText: '取消',
|
||||
success: (res) => { if (res.confirm) wx.navigateTo({ url: '/pages/profile-edit/profile-edit' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showLoading({ title: '提交中...', mask: true })
|
||||
try {
|
||||
const res = await app.request({
|
||||
url: '/api/miniprogram/ckb/lead',
|
||||
method: 'POST',
|
||||
data: {
|
||||
userId: myUserId,
|
||||
phone: phone || undefined,
|
||||
wechatId: wechatId || undefined,
|
||||
name: (app.globalData.userInfo.nickname || '').trim() || undefined,
|
||||
targetUserId,
|
||||
targetNickname: targetNickname || undefined,
|
||||
source: 'member_detail_avatar'
|
||||
}
|
||||
})
|
||||
wx.hideLoading()
|
||||
if (res && res.success) {
|
||||
wx.setStorageSync('lead_last_submit_ts', Date.now())
|
||||
wx.showToast({ title: res.message || '提交成功,对方会尽快联系您', icon: 'success' })
|
||||
} else {
|
||||
wx.showToast({ title: (res && res.message) || '提交失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: (e && e.message) || '提交失败', icon: 'none' })
|
||||
}
|
||||
await soulBridge.submitCkbLead(app, {
|
||||
targetUserId,
|
||||
targetNickname,
|
||||
source: 'member_detail_avatar',
|
||||
phoneModalContent: '请先填写手机号(必填),以便对方通过获客计划联系您'
|
||||
})
|
||||
},
|
||||
|
||||
_ensureUnlockedForLink(field) {
|
||||
|
||||
@@ -9,6 +9,12 @@ const { formatStatNum } = require('../../utils/util.js')
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
const { cleanSingleLineField } = require('../../utils/contentParser.js')
|
||||
|
||||
/** 与 referral 一致:提现需已绑定微信号(便于到账核对) */
|
||||
function hasWechatIdBound() {
|
||||
const ui = app.globalData.userInfo
|
||||
return !!(ui && (ui.wechat || ui.wechatId || wx.getStorageSync('user_wechat')))
|
||||
}
|
||||
|
||||
/** 是否视为「单章解锁」类订单(排除全书/VIP 等聚合商品名) */
|
||||
function isSectionUnlockOrder(o) {
|
||||
const name = String(o.product_name || o.title || '').trim()
|
||||
@@ -35,7 +41,7 @@ Page({
|
||||
userInfo: null,
|
||||
|
||||
// 统计数据
|
||||
totalSections: 62,
|
||||
totalSections: 0, // 来自 app.getTotalSections() 或 dashboard-stats
|
||||
readCount: 0,
|
||||
referralCount: 0,
|
||||
earnings: '-',
|
||||
@@ -961,7 +967,19 @@ Page({
|
||||
wx.showToast({ title: '暂无可提现金额', icon: 'none' })
|
||||
return
|
||||
}
|
||||
await this.ensureContactInfo(() => this.doWithdraw(amount))
|
||||
if (!hasWechatIdBound()) {
|
||||
wx.showModal({
|
||||
title: '请先绑定微信号',
|
||||
content: '提现需先绑定微信号,便于到账核对。请到「设置」中绑定后再提现。',
|
||||
confirmText: '去绑定',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) wx.navigateTo({ url: '/pages/settings/settings' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
this.doWithdraw(amount)
|
||||
},
|
||||
|
||||
async doWithdraw(amount) {
|
||||
@@ -980,6 +998,16 @@ Page({
|
||||
this.loadWalletBalance()
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
const r = e.response || {}
|
||||
if (r.needBind || r.needBindWechat) {
|
||||
wx.showModal({
|
||||
title: r.needBindWechat ? '请先绑定微信号' : '需要绑定微信',
|
||||
content: r.needBindWechat ? '请到「设置」中绑定微信号后再提现,便于到账核对。' : '请先在设置中绑定微信账号后再提现',
|
||||
confirmText: '去绑定',
|
||||
success: (mr) => { if (mr.confirm) wx.navigateTo({ url: '/pages/settings/settings' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: e.message || '提现失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ const accessManager = require('../../utils/chapterAccessManager')
|
||||
const readingTracker = require('../../utils/readingTracker')
|
||||
const { parseScene } = require('../../utils/scene.js')
|
||||
const contentParser = require('../../utils/contentParser.js')
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
|
||||
const app = getApp()
|
||||
@@ -92,7 +93,7 @@ Page({
|
||||
// 价格
|
||||
sectionPrice: 1,
|
||||
fullBookPrice: 9.9,
|
||||
totalSections: 62,
|
||||
totalSections: 0, // 来自 app.getTotalSections() 或 book/parts
|
||||
|
||||
// 弹窗
|
||||
showShareModal: false,
|
||||
@@ -121,6 +122,9 @@ Page({
|
||||
// 审核模式:隐藏购买按钮
|
||||
auditMode: false,
|
||||
|
||||
// 分润比例(来自 config.shareRate,用于分享提示文案)
|
||||
shareRate: 90,
|
||||
|
||||
// 好友从代付分享进入:待自动领取的 requestSn
|
||||
pendingGiftRequestSn: '',
|
||||
},
|
||||
@@ -189,7 +193,8 @@ Page({
|
||||
sectionMid: mid || null,
|
||||
loading: true,
|
||||
accessState: 'unknown',
|
||||
pendingGiftRequestSn: giftRequestSn || ''
|
||||
pendingGiftRequestSn: giftRequestSn || '',
|
||||
totalSections: app.getTotalSections()
|
||||
})
|
||||
|
||||
if (ref) {
|
||||
@@ -200,9 +205,12 @@ Page({
|
||||
|
||||
try {
|
||||
const config = await accessManager.fetchLatestConfig()
|
||||
const shareRate = (config && config.shareRate != null) ? config.shareRate : 90
|
||||
this.setData({
|
||||
sectionPrice: config.prices?.section ?? 1,
|
||||
fullBookPrice: config.prices?.fullbook ?? 9.9
|
||||
fullBookPrice: config.prices?.fullbook ?? 9.9,
|
||||
shareRate,
|
||||
totalSections: app.getTotalSections()
|
||||
})
|
||||
|
||||
// 统一:先拉章节数据,用 isFree/price===0 判断免费
|
||||
@@ -675,71 +683,13 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 边界:未登录→去登录;无手机/微信号→去资料编辑;重复同一人→本地 key 去重
|
||||
// 存客宝留资:统一 soulBridge.submitCkbLead(与会员详情点头像同链路)
|
||||
async _doMentionAddFriend(targetUserId, targetNickname) {
|
||||
const app = getApp()
|
||||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '请先登录后再添加好友',
|
||||
confirmText: '去登录',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) wx.switchTab({ url: '/pages/my/my' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
const myUserId = app.globalData.userInfo.id
|
||||
let phone = (app.globalData.userInfo.phone || wx.getStorageSync('user_phone') || '').trim().replace(/\s/g, '')
|
||||
let wechatId = (app.globalData.userInfo.wechatId || app.globalData.userInfo.wechat_id || wx.getStorageSync('user_wechat') || '').trim()
|
||||
if (!phone || !/^1[3-9]\d{9}$/.test(phone)) {
|
||||
try {
|
||||
const profileRes = await app.request({ url: `/api/miniprogram/user/profile?userId=${myUserId}`, silent: true })
|
||||
if (profileRes?.success && profileRes.data) {
|
||||
phone = (profileRes.data.phone || wx.getStorageSync('user_phone') || '').trim().replace(/\s/g, '')
|
||||
wechatId = (profileRes.data.wechatId || profileRes.data.wechat_id || wx.getStorageSync('user_wechat') || '').trim()
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!phone || !/^1[3-9]\d{9}$/.test(phone)) {
|
||||
wx.showModal({
|
||||
title: '完善资料',
|
||||
content: '请先填写手机号(必填),以便对方联系您',
|
||||
confirmText: '去填写',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) wx.navigateTo({ url: '/pages/profile-edit/profile-edit' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showLoading({ title: '提交中...', mask: true })
|
||||
try {
|
||||
const res = await app.request({
|
||||
url: '/api/miniprogram/ckb/lead',
|
||||
method: 'POST',
|
||||
data: {
|
||||
userId: myUserId,
|
||||
phone: phone || undefined,
|
||||
wechatId: wechatId || undefined,
|
||||
name: (app.globalData.userInfo.nickname || '').trim() || undefined,
|
||||
targetUserId,
|
||||
targetNickname: targetNickname || undefined,
|
||||
source: 'article_mention'
|
||||
}
|
||||
})
|
||||
wx.hideLoading()
|
||||
if (res && res.success) {
|
||||
wx.setStorageSync('lead_last_submit_ts', Date.now())
|
||||
wx.showToast({ title: res.message || '提交成功,对方会尽快联系您', icon: 'success' })
|
||||
} else {
|
||||
wx.showToast({ title: (res && res.message) || '提交失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: (e && e.message) || '提交失败', icon: 'none' })
|
||||
}
|
||||
await soulBridge.submitCkbLead(app, {
|
||||
targetUserId,
|
||||
targetNickname,
|
||||
source: 'article_mention'
|
||||
})
|
||||
},
|
||||
|
||||
// 分享弹窗
|
||||
@@ -848,24 +798,8 @@ Page({
|
||||
}
|
||||
const payParams = payRes.data.payParams
|
||||
const orderSn = payRes.data.orderSn
|
||||
await new Promise((resolve, reject) => {
|
||||
wx.requestPayment({
|
||||
timeStamp: payParams.timeStamp,
|
||||
nonceStr: payParams.nonceStr,
|
||||
package: payParams.package,
|
||||
signType: payParams.signType || 'RSA',
|
||||
paySign: payParams.paySign,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
|
||||
// 3) 主动同步(与其他支付流程一致)
|
||||
if (orderSn) {
|
||||
try {
|
||||
await app.request(`/api/miniprogram/pay?orderSn=${encodeURIComponent(orderSn)}`, { silent: true })
|
||||
} catch (e) {}
|
||||
}
|
||||
await soulBridge.requestWxJsapiPayment(payParams)
|
||||
await soulBridge.syncOrderStatusQuery(app, orderSn)
|
||||
|
||||
wx.showToast({ title: '支付成功', icon: 'success' })
|
||||
this.setData({ giftPaid: true, giftRequestSn: requestSn, giftPaying: false })
|
||||
@@ -883,8 +817,7 @@ Page({
|
||||
|
||||
// 复制链接
|
||||
copyLink() {
|
||||
const userInfo = app.globalData.userInfo
|
||||
const referralCode = userInfo?.referralCode || ''
|
||||
const referralCode = app.getMyReferralCode() || ''
|
||||
const shareUrl = `https://soul.quwanzhi.com/read/${this.data.sectionId}${referralCode ? '?ref=' + referralCode : ''}`
|
||||
|
||||
wx.setClipboardData({
|
||||
@@ -900,9 +833,10 @@ Page({
|
||||
copyShareText() {
|
||||
const { section } = this.data
|
||||
|
||||
const total = app.getTotalSections()
|
||||
const shareText = `🔥 刚看完这篇《${section?.title || '卡若创业派对'}》,太上头了!
|
||||
|
||||
62个真实商业案例,每个都是从0到1的实战经验。私域运营、资源整合、商业变现,干货满满。
|
||||
${total}个真实商业案例,每个都是从0到1的实战经验。私域运营、资源整合、商业变现,干货满满。
|
||||
|
||||
推荐给正在创业或想创业的朋友,搜"卡若创业派对"小程序就能看!
|
||||
|
||||
@@ -1198,7 +1132,7 @@ Page({
|
||||
try {
|
||||
// 0. 尝试余额支付(若余额足够)
|
||||
const userId = app.globalData.userInfo?.id
|
||||
const referralCode = wx.getStorageSync('referral_code') || ''
|
||||
const referralCode = soulBridge.getReferralCodeForPay(app)
|
||||
if (userId) {
|
||||
try {
|
||||
const balanceRes = await app.request({ url: `/api/miniprogram/balance?userId=${userId}`, silent: true })
|
||||
@@ -1262,14 +1196,9 @@ Page({
|
||||
let paymentData = null
|
||||
|
||||
try {
|
||||
// 获取章节完整名称用于支付描述
|
||||
const sectionTitle = this.data.section?.title || sectionId
|
||||
const description = type === 'fullbook'
|
||||
? '《一场Soul的创业实验》全书'
|
||||
: `章节${sectionId}-${sectionTitle.length > 20 ? sectionTitle.slice(0, 20) + '...' : sectionTitle}`
|
||||
|
||||
// 邀请码:谁邀请了我(从落地页 ref 或 storage 带入),会写入订单 referrer_id / referral_code 便于分销与对账
|
||||
const referralCode = wx.getStorageSync('referral_code') || ''
|
||||
const description = soulBridge.buildSectionPayDescription(type, sectionId, sectionTitle)
|
||||
const referralCode = soulBridge.getReferralCodeForPay(app)
|
||||
const res = await app.request('/api/miniprogram/pay', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
@@ -1321,18 +1250,11 @@ Page({
|
||||
console.log('[Pay] 调起微信支付, paymentData:', paymentData)
|
||||
|
||||
try {
|
||||
await this.callWechatPay(paymentData)
|
||||
|
||||
// 4. 【关键】主动向微信查询订单状态并同步到本地(不依赖回调,解决订单一直 created 的问题)
|
||||
await soulBridge.requestWxJsapiPayment(paymentData)
|
||||
|
||||
const orderSn = paymentData._orderSn || paymentData.orderSn
|
||||
if (orderSn) {
|
||||
try {
|
||||
await app.request(`/api/miniprogram/pay?orderSn=${encodeURIComponent(orderSn)}`, { silent: true })
|
||||
console.log('[Pay] 已主动同步订单状态:', orderSn)
|
||||
} catch (e) {
|
||||
console.warn('[Pay] 主动同步订单失败,继续刷新购买状态:', e)
|
||||
}
|
||||
}
|
||||
await soulBridge.syncOrderStatusQuery(app, orderSn)
|
||||
if (orderSn) console.log('[Pay] 已主动同步订单状态:', orderSn)
|
||||
|
||||
// 5. 【标准流程】刷新权限并解锁内容
|
||||
console.log('[Pay] 微信支付成功!')
|
||||
@@ -1467,21 +1389,6 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
// 调用微信支付
|
||||
callWechatPay(paymentData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.requestPayment({
|
||||
timeStamp: paymentData.timeStamp,
|
||||
nonceStr: paymentData.nonceStr,
|
||||
package: paymentData.package,
|
||||
signType: paymentData.signType || 'MD5',
|
||||
paySign: paymentData.paySign,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到上一篇
|
||||
goToPrev() {
|
||||
if (this.data.prevSection) {
|
||||
@@ -1728,11 +1635,13 @@ Page({
|
||||
|
||||
try {
|
||||
const config = await accessManager.fetchLatestConfig()
|
||||
const shareRate = (config && config.shareRate != null) ? config.shareRate : 90
|
||||
this.setData({
|
||||
sectionPrice: config.prices?.section ?? 1,
|
||||
fullBookPrice: config.prices?.fullbook ?? 9.9
|
||||
fullBookPrice: config.prices?.fullbook ?? 9.9,
|
||||
shareRate
|
||||
})
|
||||
|
||||
|
||||
// 重新拉取章节,用 isFree/price 判断免费
|
||||
const chapterRes = await app.request({
|
||||
url: this._getChapterUrl({}),
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="share-tip-inline" wx:if="{{!auditMode}}">
|
||||
<text class="share-tip-text">分享后好友购买,你可获得 90% 收益</text>
|
||||
<text class="share-tip-text">分享后好友购买,你可获得 {{shareRate || 90}}% 收益</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ Page({
|
||||
posterReferralLink: '',
|
||||
posterNickname: '',
|
||||
posterNicknameInitial: '',
|
||||
posterCaseCount: 62
|
||||
posterCaseCount: 0 // 来自 app.getTotalSections(),initData 后更新
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -174,6 +174,7 @@ Page({
|
||||
minWithdrawAmount: minWithdrawAmount,
|
||||
bindingDays: realData?.bindingDays ?? 30,
|
||||
userDiscount: realData?.userDiscount ?? 5,
|
||||
posterCaseCount: app.getTotalSections(),
|
||||
|
||||
// 统计
|
||||
referralCount: realData?.referralCount || realData?.stats?.totalBindings || activeBindings.length + convertedBindings.length,
|
||||
@@ -545,9 +546,10 @@ Page({
|
||||
|
||||
// 分享到朋友圈 - 随机文案
|
||||
shareToMoments() {
|
||||
const total = app.getTotalSections()
|
||||
// 10条随机文案,基于书的内容
|
||||
const shareTexts = [
|
||||
`🔥 在派对房里听到的真实故事,比虚构的小说精彩100倍!\n\n电动车出租月入5万、私域一年赚1000万、一个人的公司月入10万...\n\n62个真实案例,搜"卡若创业派对"小程序看全部!\n\n#创业 #私域 #商业`,
|
||||
`🔥 在派对房里听到的真实故事,比虚构的小说精彩100倍!\n\n电动车出租月入5万、私域一年赚1000万、一个人的公司月入10万...\n\n${total}个真实案例,搜"卡若创业派对"小程序看全部!\n\n#创业 #私域 #商业`,
|
||||
|
||||
`💡 今天终于明白:会赚钱的人,都在用"流量杠杆"\n\n抖音、Soul、飞书...同一套内容,撬动不同平台的流量。\n\n《卡若创业派对》里的实战方法,受用终身!\n\n#流量 #副业 #创业派对`,
|
||||
|
||||
@@ -654,37 +656,31 @@ Page({
|
||||
method: 'POST',
|
||||
data: { userId, amount }
|
||||
})
|
||||
|
||||
|
||||
wx.hideLoading()
|
||||
|
||||
if (res.success) {
|
||||
wx.showModal({
|
||||
title: '提现申请已提交 ✅',
|
||||
content: res.message || '正在审核中,通过后会自动到账您的微信零钱',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
|
||||
// 刷新数据(此时待审核金额会增加,可提现金额会减少)
|
||||
this.initData()
|
||||
} else {
|
||||
if (res.needBind || res.needBindWechat) {
|
||||
wx.showModal({
|
||||
title: res.needBindWechat ? '请先绑定微信号' : '需要绑定微信',
|
||||
content: res.needBindWechat ? '请到「设置」中绑定微信号后再提现,便于到账核对。' : '请先在设置中绑定微信账号后再提现',
|
||||
confirmText: '去绑定',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) wx.navigateTo({ url: '/pages/settings/settings' })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
wx.showToast({ title: res.message || res.error || '提现失败', icon: 'none', duration: 3000 })
|
||||
}
|
||||
}
|
||||
wx.showModal({
|
||||
title: '提现申请已提交 ✅',
|
||||
content: res.message || '正在审核中,通过后会自动到账您的微信零钱',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
this.initData()
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
console.error('[Referral] 提现失败:', e)
|
||||
wx.showToast({ title: '提现失败,请重试', icon: 'none' })
|
||||
const r = e.response || {}
|
||||
if (r.needBind || r.needBindWechat) {
|
||||
wx.showModal({
|
||||
title: r.needBindWechat ? '请先绑定微信号' : '需要绑定微信',
|
||||
content: r.needBindWechat ? '请到「设置」中绑定微信号后再提现,便于到账核对。' : '请先在设置中绑定微信账号后再提现',
|
||||
confirmText: '去绑定',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) wx.navigateTo({ url: '/pages/settings/settings' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: e.message || '提现失败,请重试', icon: 'none', duration: 3000 })
|
||||
}
|
||||
},
|
||||
|
||||
@@ -860,8 +856,9 @@ Page({
|
||||
onShareTimeline() {
|
||||
const ref = this.data.referralCode || app.getMyReferralCode()
|
||||
console.log('[Referral] 分享到朋友圈,推荐码:', ref)
|
||||
const total = app.getTotalSections()
|
||||
return {
|
||||
title: `卡若创业派对 - 62个真实商业案例`,
|
||||
title: `卡若创业派对 - ${total}个真实商业案例`,
|
||||
query: ref ? `ref=${ref}` : ''
|
||||
// 不设置 imageUrl,使用小程序默认截图
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const accessManager = require('../../utils/chapterAccessManager')
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
const app = getApp()
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
|
||||
@@ -90,7 +91,7 @@ Page({
|
||||
const amount = this.data.price
|
||||
try {
|
||||
// 0. 尝试余额支付(若余额足够)
|
||||
const referralCode = wx.getStorageSync('referral_code') || ''
|
||||
const referralCode = soulBridge.getReferralCodeForPay(app)
|
||||
try {
|
||||
const balanceRes = await app.request({ url: `/api/miniprogram/balance?userId=${userId}`, silent: true })
|
||||
const balance = balanceRes?.data?.balance || 0
|
||||
@@ -117,7 +118,7 @@ Page({
|
||||
console.warn('[VIP] 余额支付失败,改用微信支付:', e)
|
||||
}
|
||||
|
||||
// 1. 微信支付
|
||||
// 1. 微信支付(带推荐码,与章节/匹配支付一致,便于分销归因)
|
||||
const payRes = await app.request('/api/miniprogram/pay', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
@@ -126,18 +127,21 @@ Page({
|
||||
productType: 'vip',
|
||||
productId: 'vip_annual',
|
||||
amount,
|
||||
description: '卡若创业派对VIP年度会员(365天)'
|
||||
description: '卡若创业派对VIP年度会员(365天)',
|
||||
referralCode: soulBridge.getReferralCodeForPay(app) || undefined
|
||||
}
|
||||
})
|
||||
if (payRes?.success && payRes.data?.payParams) {
|
||||
wx.requestPayment({
|
||||
...payRes.data.payParams,
|
||||
success: async () => {
|
||||
wx.showToast({ title: 'VIP开通成功', icon: 'success' })
|
||||
await this._onVipPaymentSuccess()
|
||||
},
|
||||
fail: () => wx.showToast({ title: '支付取消', icon: 'none' })
|
||||
})
|
||||
try {
|
||||
await soulBridge.requestWxJsapiPayment(payRes.data.payParams)
|
||||
await soulBridge.syncOrderStatusQuery(app, payRes.data.orderSn)
|
||||
wx.showToast({ title: 'VIP开通成功', icon: 'success' })
|
||||
await this._onVipPaymentSuccess()
|
||||
} catch (e) {
|
||||
const msg = (e && e.errMsg) ? String(e.errMsg) : ''
|
||||
if (msg.indexOf('cancel') !== -1) wx.showToast({ title: '支付取消', icon: 'none' })
|
||||
else wx.showToast({ title: '支付失败', icon: 'none' })
|
||||
}
|
||||
} else {
|
||||
wx.showToast({ title: payRes?.error || '支付参数获取失败', icon: 'none' })
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const app = getApp()
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
|
||||
Page({
|
||||
@@ -114,23 +115,22 @@ Page({
|
||||
})
|
||||
const params = (payRes && payRes.data && payRes.data.payParams) ? payRes.data.payParams : (payRes && payRes.payParams ? payRes.payParams : null)
|
||||
if (params) {
|
||||
wx.requestPayment({
|
||||
...params,
|
||||
success: async () => {
|
||||
// Confirm the recharge
|
||||
await app.request({
|
||||
url: '/api/miniprogram/balance/recharge/confirm',
|
||||
method: 'POST',
|
||||
data: { orderSn: res.data.orderSn }
|
||||
})
|
||||
wx.showToast({ title: '充值成功', icon: 'success' })
|
||||
this.loadBalance()
|
||||
this.loadTransactions()
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '支付取消', icon: 'none' })
|
||||
}
|
||||
})
|
||||
try {
|
||||
await soulBridge.requestWxJsapiPayment(params)
|
||||
await soulBridge.syncOrderStatusQuery(app, payRes.data && payRes.data.orderSn)
|
||||
await app.request({
|
||||
url: '/api/miniprogram/balance/recharge/confirm',
|
||||
method: 'POST',
|
||||
data: { orderSn: res.data.orderSn }
|
||||
})
|
||||
wx.showToast({ title: '充值成功', icon: 'success' })
|
||||
this.loadBalance()
|
||||
this.loadTransactions()
|
||||
} catch (e) {
|
||||
const msg = (e && e.errMsg) ? String(e.errMsg) : ''
|
||||
if (msg.indexOf('cancel') !== -1) wx.showToast({ title: '支付取消', icon: 'none' })
|
||||
else wx.showToast({ title: '支付失败', icon: 'none' })
|
||||
}
|
||||
} else {
|
||||
wx.showToast({ title: '创建支付失败', icon: 'none' })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user