feat: 小程序超级个体/个人资料/CKB获客;VIP列表展示过滤;管理端与API联调
- 超级个体:去掉首位特例;列表仅展示有头像且非微信默认昵称(vip.go) - 个人资料:居中头像、低调联系方式、点头像优先走存客宝 lead(ckbLeadToken) - 阅读页分享朋友圈复制与 toast 去重 - soul-api: miniprogram users 带 ckbLeadToken;其它 handler 与路由调整 - 脚本:content_upload、miniprogram 上传辅助等 Made-with: Cursor
This commit is contained in:
@@ -9,13 +9,16 @@ const { checkAndExecute } = require('./utils/ruleEngine.js')
|
||||
const DEFAULT_APP_ID = 'wxb8bbb2b10dec74aa'
|
||||
const DEFAULT_MCH_ID = '1318592501'
|
||||
const DEFAULT_WITHDRAW_TMPL_ID = 'u3MbZGPRkrZIk-I7QdpwzFxnO_CeQPaCWF2FkiIablE'
|
||||
// 与上传版本号对齐;设置页展示优先用 wx.getAccountInfoSync().miniProgram.version(正式版),否则用本字段
|
||||
const APP_DISPLAY_VERSION = '1.7.1'
|
||||
|
||||
App({
|
||||
globalData: {
|
||||
// API 基础地址:开发时修改下面一行切换环境
|
||||
// baseUrl: "https://soulapi.quwanzhi.com",
|
||||
baseUrl: 'http://localhost:8080', // 开发
|
||||
// baseUrl: 'https://souldev.quwanzhi.com', // 测试
|
||||
// 与微信后台上传版本号一致,供设置页等展示(避免与线上 version 字段混淆)
|
||||
appDisplayVersion: APP_DISPLAY_VERSION,
|
||||
|
||||
// API:仓库默认生产;release 强制生产;develop/trial 可读 storage「apiBaseUrl」或用 env-switch
|
||||
baseUrl: 'https://soulapi.quwanzhi.com',
|
||||
// 小程序配置 - 真实AppID
|
||||
appId: DEFAULT_APP_ID,
|
||||
|
||||
@@ -30,9 +33,14 @@ App({
|
||||
openId: null, // 微信openId,支付必需
|
||||
isLoggedIn: false,
|
||||
|
||||
// 阅读页 @ 解析:/config/read-extras 的 mentionPersons(与后台 persons + token 一致)
|
||||
mentionPersons: [],
|
||||
// 是否已成功拉取过 read-extras(避免仅 linkTags 有缓存时永远拿不到 mentionPersons)
|
||||
readExtrasCacheValid: false,
|
||||
|
||||
// 书籍数据(bookData 由 chapters-by-part 等逐步填充,不再预加载 all-chapters)
|
||||
bookData: null,
|
||||
totalSections: 62,
|
||||
totalSections: 90,
|
||||
|
||||
// 购买记录
|
||||
purchasedSections: [],
|
||||
@@ -47,6 +55,9 @@ App({
|
||||
// 推荐绑定
|
||||
pendingReferralCode: null, // 待绑定的推荐码
|
||||
|
||||
// 客服微信号(从系统配置加载,默认值兜底)
|
||||
serviceWechat: '28533368',
|
||||
|
||||
// 主题配置
|
||||
theme: {
|
||||
brandColor: '#00CED1',
|
||||
@@ -81,14 +92,39 @@ App({
|
||||
// config 统一缓存(5min),减少重复请求
|
||||
configCache: null,
|
||||
configCacheExpires: 0,
|
||||
// VIP 联系方式检测:上次检测时间戳,onShow 节流 5 分钟
|
||||
// VIP 联系方式检测:上次检测时间戳,onShow 短节流(避免与 launch 重复打满接口)
|
||||
lastVipContactCheck: 0,
|
||||
// 头像昵称检测:上次检测时间戳,onShow 节流 5 分钟
|
||||
// 头像昵称检测:上次检测时间戳(与 VIP 检测同周期刷新)
|
||||
lastAvatarNicknameCheck: 0,
|
||||
},
|
||||
|
||||
|
||||
/** 正式版强制生产 API,避免误传 localhost 导致审核/线上全挂 */
|
||||
initApiBaseUrl() {
|
||||
const PRODUCTION = 'https://soulapi.quwanzhi.com'
|
||||
const KEY = 'apiBaseUrl'
|
||||
try {
|
||||
const info = wx.getAccountInfoSync?.()
|
||||
const env = info?.miniProgram?.envVersion || 'release'
|
||||
if (env === 'release') {
|
||||
this.globalData.baseUrl = PRODUCTION
|
||||
try {
|
||||
const saved = wx.getStorageSync(KEY)
|
||||
if (saved && saved !== PRODUCTION) wx.removeStorageSync(KEY)
|
||||
} catch (_) {}
|
||||
return
|
||||
}
|
||||
const saved = wx.getStorageSync(KEY)
|
||||
if (saved && typeof saved === 'string' && /^https?:\/\//.test(saved)) {
|
||||
this.globalData.baseUrl = String(saved).replace(/\/$/, '')
|
||||
}
|
||||
} catch (_) {
|
||||
this.globalData.baseUrl = PRODUCTION
|
||||
}
|
||||
},
|
||||
|
||||
onLaunch(options) {
|
||||
this.initApiBaseUrl()
|
||||
// 昵称等隐私组件需先授权:input type="nickname" 不会主动触发,需配合 wx.requirePrivacyAuthorize 使用
|
||||
if (typeof wx.onNeedPrivacyAuthorization === 'function') {
|
||||
wx.onNeedPrivacyAuthorization((resolve) => {
|
||||
@@ -169,10 +205,10 @@ App({
|
||||
this.globalData.lastMpConfigCheck = now
|
||||
this.getAuditMode()
|
||||
}
|
||||
// 从后台切回:先 VIP 强制跳转,再头像/昵称,节流 5 分钟
|
||||
const throttle = 5 * 60 * 1000
|
||||
// 从后台切回:刷新 VIP/头像引导(vipGuideThrottleMs=0 表示不限制间隔)
|
||||
const vipGuideThrottleMs = 0
|
||||
if (this.globalData.isLoggedIn && this.globalData.userInfo?.id) {
|
||||
if (!this.globalData.lastVipContactCheck || now - this.globalData.lastVipContactCheck > throttle) {
|
||||
if (vipGuideThrottleMs <= 0 || !this.globalData.lastVipContactCheck || now - this.globalData.lastVipContactCheck > vipGuideThrottleMs) {
|
||||
this.globalData.lastVipContactCheck = now
|
||||
this.globalData.lastAvatarNicknameCheck = now
|
||||
setTimeout(() => this.checkVipContactRequiredAndGuide(), 500)
|
||||
@@ -558,9 +594,6 @@ App({
|
||||
*/
|
||||
async checkVipContactRequiredAndGuide() {
|
||||
if (!this.globalData.isLoggedIn || !this.globalData.userInfo?.id) return
|
||||
const now = Date.now()
|
||||
if (this._lastVipGuideRun && now - this._lastVipGuideRun < 3000) return // 3 秒内不重复执行,避免 onLaunch+onShow 双重触发
|
||||
this._lastVipGuideRun = now
|
||||
const userId = this.globalData.userInfo.id
|
||||
try {
|
||||
const pages = getCurrentPages()
|
||||
@@ -688,10 +721,11 @@ App({
|
||||
* 获取阅读页扩展配置(linkTags、linkedMiniprograms),懒加载
|
||||
*/
|
||||
async getReadExtras() {
|
||||
if (Array.isArray(this.globalData.linkTagsConfig) && this.globalData.linkTagsConfig.length > 0) {
|
||||
if (this.globalData.readExtrasCacheValid) {
|
||||
return {
|
||||
linkTags: this.globalData.linkTagsConfig,
|
||||
linkedMiniprograms: this.globalData.linkedMiniprograms || []
|
||||
linkTags: this.globalData.linkTagsConfig || [],
|
||||
linkedMiniprograms: this.globalData.linkedMiniprograms || [],
|
||||
mentionPersons: this.globalData.mentionPersons || [],
|
||||
}
|
||||
}
|
||||
try {
|
||||
@@ -699,10 +733,18 @@ App({
|
||||
if (res) {
|
||||
if (Array.isArray(res.linkTags)) this.globalData.linkTagsConfig = res.linkTags
|
||||
if (Array.isArray(res.linkedMiniprograms)) this.globalData.linkedMiniprograms = res.linkedMiniprograms
|
||||
if (Array.isArray(res.mentionPersons)) this.globalData.mentionPersons = res.mentionPersons
|
||||
else this.globalData.mentionPersons = []
|
||||
this.globalData.readExtrasCacheValid = true
|
||||
return res
|
||||
}
|
||||
} catch (e) {}
|
||||
return { linkTags: [], linkedMiniprograms: [] }
|
||||
if (!Array.isArray(this.globalData.mentionPersons)) this.globalData.mentionPersons = []
|
||||
return {
|
||||
linkTags: this.globalData.linkTagsConfig || [],
|
||||
linkedMiniprograms: this.globalData.linkedMiniprograms || [],
|
||||
mentionPersons: this.globalData.mentionPersons,
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -759,14 +801,14 @@ App({
|
||||
|
||||
/**
|
||||
* 小程序更新检测(基于 wx.getUpdateManager)
|
||||
* - 启动时检测;从后台切回前台时也检测(间隔至少 5 分钟,避免频繁请求)
|
||||
* - 启动时检测;从后台切回前台时也检测(短间隔即可,避免用户感知「很久才检查更新」)
|
||||
*/
|
||||
checkUpdate() {
|
||||
try {
|
||||
if (!wx.canIUse('getUpdateManager')) return
|
||||
const now = Date.now()
|
||||
const lastCheck = this.globalData.lastUpdateCheck || 0
|
||||
if (lastCheck && now - lastCheck < 5 * 60 * 1000) return // 5 分钟内不重复检测
|
||||
if (lastCheck && now - lastCheck < 60 * 1000) return // 1 分钟内不重复检测
|
||||
this.globalData.lastUpdateCheck = now
|
||||
|
||||
const updateManager = wx.getUpdateManager()
|
||||
@@ -1038,13 +1080,6 @@ App({
|
||||
return null
|
||||
},
|
||||
|
||||
// 模拟登录已废弃 - 不再使用
|
||||
// 现在必须使用真实的微信登录获取openId作为唯一标识
|
||||
mockLogin() {
|
||||
console.warn('[App] mockLogin已废弃,请使用真实登录')
|
||||
return null
|
||||
},
|
||||
|
||||
// 手机号登录:需同时传 wx.login 的 code 与 getPhoneNumber 的 phoneCode
|
||||
async loginWithPhone(phoneCode) {
|
||||
if (!this.ensureFullAppForAuth()) {
|
||||
|
||||
Reference in New Issue
Block a user