同步
This commit is contained in:
@@ -9,7 +9,9 @@ const { checkAndExecute } = require('./utils/ruleEngine.js')
|
||||
const DEFAULT_APP_ID = 'wxb8bbb2b10dec74aa'
|
||||
const DEFAULT_MCH_ID = '1318592501'
|
||||
const DEFAULT_WITHDRAW_TMPL_ID = 'u3MbZGPRkrZIk-I7QdpwzFxnO_CeQPaCWF2FkiIablE'
|
||||
const PRODUCTION_BASE_URL = 'https://soulapi.quwanzhi.com'
|
||||
// baseUrl 手动切换(注释方式):
|
||||
const API_BASE_URL = 'http://localhost:8080'
|
||||
// const API_BASE_URL = 'https://soulapi.quwanzhi.com'
|
||||
const CONFIG_CACHE_KEY = 'mpConfigCacheV1'
|
||||
// 与上传版本号对齐;设置页展示优先用 wx.getAccountInfoSync().miniProgram.version(正式版),否则用本字段
|
||||
const APP_DISPLAY_VERSION = '1.7.2'
|
||||
@@ -19,8 +21,8 @@ App({
|
||||
// 与微信后台上传版本号一致,供设置页等展示(避免与线上 version 字段混淆)
|
||||
appDisplayVersion: APP_DISPLAY_VERSION,
|
||||
|
||||
// API:仓库默认生产;release 强制生产;develop/trial 可读 storage「apiBaseUrl」或用 env-switch
|
||||
baseUrl: 'https://soulapi.quwanzhi.com',
|
||||
// API:仅使用代码常量手动切换,不再使用运行时开关
|
||||
baseUrl: API_BASE_URL,
|
||||
// 小程序配置 - 真实AppID
|
||||
appId: DEFAULT_APP_ID,
|
||||
|
||||
@@ -98,39 +100,17 @@ App({
|
||||
lastVipContactCheck: 0,
|
||||
// 头像昵称检测:上次检测时间戳(与 VIP 检测同周期刷新)
|
||||
lastAvatarNicknameCheck: 0,
|
||||
// 登录后规则引擎触发时间(用于与本地引导去重,避免短时间二次弹窗)
|
||||
lastAfterLoginRuleCheck: 0,
|
||||
/** MBTI → 默认头像 URL(/api/miniprogram/config/mbti-avatars),供推广海报等 */
|
||||
mbtiAvatarsMap: {},
|
||||
mbtiAvatarsExpires: 0,
|
||||
},
|
||||
|
||||
|
||||
/** 正式版强制生产 API,避免误传 localhost 导致审核/线上全挂 */
|
||||
initApiBaseUrl() {
|
||||
const KEY = 'apiBaseUrl'
|
||||
try {
|
||||
const info = wx.getAccountInfoSync?.()
|
||||
const env = info?.miniProgram?.envVersion || 'release'
|
||||
if (env === 'release') {
|
||||
this.globalData.baseUrl = PRODUCTION_BASE_URL
|
||||
try {
|
||||
const saved = wx.getStorageSync(KEY)
|
||||
if (saved && saved !== PRODUCTION_BASE_URL) wx.removeStorageSync(KEY)
|
||||
} catch (_) {}
|
||||
return
|
||||
}
|
||||
const saved = wx.getStorageSync(KEY)
|
||||
if (saved && typeof saved === 'string' && /^https?:\/\//.test(saved)) {
|
||||
this.globalData.baseUrl = String(saved).replace(/\/$/, '')
|
||||
} else {
|
||||
this.globalData.baseUrl = PRODUCTION_BASE_URL
|
||||
}
|
||||
} catch (_) {
|
||||
this.globalData.baseUrl = PRODUCTION_BASE_URL
|
||||
}
|
||||
},
|
||||
|
||||
onLaunch(options) {
|
||||
this.initApiBaseUrl()
|
||||
// baseUrl 固定取 API_BASE_URL(通过注释切换)
|
||||
this.globalData.baseUrl = API_BASE_URL
|
||||
// 昵称等隐私组件需先授权:input type="nickname" 不会主动触发,需配合 wx.requirePrivacyAuthorize 使用
|
||||
if (typeof wx.onNeedPrivacyAuthorization === 'function') {
|
||||
wx.onNeedPrivacyAuthorization((resolve) => {
|
||||
@@ -616,7 +596,12 @@ App({
|
||||
const isVip = vipRes?.data?.isVip || this.globalData.isVip || false
|
||||
this.globalData.isVip = isVip
|
||||
if (!isVip) {
|
||||
this.checkAvatarNicknameAndGuide()
|
||||
const now = Date.now()
|
||||
const lastRuleCheck = Number(this.globalData.lastAfterLoginRuleCheck || 0)
|
||||
// 登录后若规则引擎刚触发过 after_login,引导由规则引擎负责,避免与本地提示连弹
|
||||
if (!lastRuleCheck || now - lastRuleCheck > 5000) {
|
||||
this.checkAvatarNicknameAndGuide()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -933,27 +918,6 @@ App({
|
||||
return (msg && String(msg).trim()) ? String(msg).trim() : defaultMsg
|
||||
},
|
||||
|
||||
_shouldFallbackToProduction(err) {
|
||||
const msg = String((err && err.errMsg) || (err && err.message) || '').toLowerCase()
|
||||
return (
|
||||
msg.includes('connection_failed') ||
|
||||
msg.includes('err_proxy_connection_failed') ||
|
||||
msg.includes('dns') ||
|
||||
msg.includes('name not resolved') ||
|
||||
msg.includes('failed to fetch') ||
|
||||
msg.includes('econnrefused') ||
|
||||
msg.includes('network') ||
|
||||
msg.includes('timeout')
|
||||
)
|
||||
},
|
||||
|
||||
_switchBaseUrlToProduction() {
|
||||
this.globalData.baseUrl = PRODUCTION_BASE_URL
|
||||
try {
|
||||
wx.setStorageSync('apiBaseUrl', PRODUCTION_BASE_URL)
|
||||
} catch (_) {}
|
||||
},
|
||||
|
||||
_requestOnce(url, options = {}, silent = false) {
|
||||
const showError = (msg) => {
|
||||
if (!silent && msg) wx.showToast({ title: msg, icon: 'none', duration: 2500 })
|
||||
@@ -972,6 +936,11 @@ App({
|
||||
},
|
||||
success: (res) => {
|
||||
const data = res.data
|
||||
const rejectWithBody = (message, body) => {
|
||||
const err = new Error(message)
|
||||
if (body != null && typeof body === 'object') err.response = body
|
||||
reject(err)
|
||||
}
|
||||
if (res.statusCode === 200) {
|
||||
if (data && data.success === false) {
|
||||
const msg = this._getApiErrorMsg(data, '操作失败')
|
||||
@@ -979,7 +948,7 @@ App({
|
||||
this.logout()
|
||||
}
|
||||
showError(msg)
|
||||
reject(new Error(msg))
|
||||
rejectWithBody(msg, data)
|
||||
return
|
||||
}
|
||||
resolve(data)
|
||||
@@ -988,12 +957,14 @@ App({
|
||||
if (res.statusCode === 401) {
|
||||
this.logout()
|
||||
showError('未授权,请重新登录')
|
||||
reject(new Error('未授权'))
|
||||
const err = new Error('未授权')
|
||||
if (data != null && typeof data === 'object') err.response = data
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
const msg = this._getApiErrorMsg(data, res.statusCode >= 500 ? '服务器异常,请稍后重试' : '请求失败')
|
||||
showError(msg)
|
||||
reject(new Error(msg))
|
||||
rejectWithBody(msg, data && typeof data === 'object' ? data : undefined)
|
||||
},
|
||||
fail: (err) => {
|
||||
const msg = (err && err.errMsg)
|
||||
@@ -1033,13 +1004,10 @@ App({
|
||||
}
|
||||
|
||||
const promise = this._requestOnce(url, options, silent).catch(async (err) => {
|
||||
const currentBase = String(this.globalData.baseUrl || '').replace(/\/$/, '')
|
||||
if (currentBase !== PRODUCTION_BASE_URL && this._shouldFallbackToProduction(err)) {
|
||||
this._switchBaseUrlToProduction()
|
||||
return this._requestOnce(url, options, silent)
|
||||
}
|
||||
const msg = (err && err.message) ? err.message : '网络异常,请重试'
|
||||
throw new Error(msg)
|
||||
const next = new Error(msg)
|
||||
if (err && err.response != null) next.response = err.response
|
||||
throw next
|
||||
})
|
||||
|
||||
if (method === 'GET') {
|
||||
@@ -1102,8 +1070,9 @@ App({
|
||||
this.globalData.vipExpireDate = user.vipExpireDate || ''
|
||||
// 首次登录注册:强制跳转 avatar-nickname 修改头像昵称(不弹窗)
|
||||
if (res.isNewUser === true && this._needsAvatarNickname(user)) {
|
||||
setTimeout(() => wx.redirectTo({ url: '/pages/avatar-nickname/avatar-nickname' }), 1000)
|
||||
setTimeout(() => wx.redirectTo({ url: '/pages/avatar-nickname/avatar-nickname?from=new_user' }), 1000)
|
||||
} else {
|
||||
this.globalData.lastAfterLoginRuleCheck = Date.now()
|
||||
checkAndExecute('after_login', null)
|
||||
setTimeout(() => this.checkVipContactRequiredAndGuide(), 1200)
|
||||
setTimeout(() => this.connectWsHeartbeat(), 2000)
|
||||
@@ -1173,8 +1142,9 @@ App({
|
||||
this.globalData.vipExpireDate = user.vipExpireDate || ''
|
||||
// 首次登录注册:强制跳转 avatar-nickname
|
||||
if (res.isNewUser === true && this._needsAvatarNickname(user)) {
|
||||
setTimeout(() => wx.redirectTo({ url: '/pages/avatar-nickname/avatar-nickname' }), 1000)
|
||||
setTimeout(() => wx.redirectTo({ url: '/pages/avatar-nickname/avatar-nickname?from=new_user' }), 1000)
|
||||
} else {
|
||||
this.globalData.lastAfterLoginRuleCheck = Date.now()
|
||||
checkAndExecute('after_login', null)
|
||||
setTimeout(() => this.checkVipContactRequiredAndGuide(), 1200)
|
||||
}
|
||||
@@ -1234,8 +1204,9 @@ App({
|
||||
|
||||
// 首次登录注册:强制跳转 avatar-nickname
|
||||
if (res.isNewUser === true && this._needsAvatarNickname(user)) {
|
||||
setTimeout(() => wx.redirectTo({ url: '/pages/avatar-nickname/avatar-nickname' }), 1000)
|
||||
setTimeout(() => wx.redirectTo({ url: '/pages/avatar-nickname/avatar-nickname?from=new_user' }), 1000)
|
||||
} else {
|
||||
this.globalData.lastAfterLoginRuleCheck = Date.now()
|
||||
checkAndExecute('after_login', null)
|
||||
setTimeout(() => this.checkVipContactRequiredAndGuide(), 1200)
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* 开发环境专用:可拖拽的 baseURL 切换悬浮按钮
|
||||
* 正式环境(release)不显示
|
||||
*/
|
||||
const PRODUCTION_URL = 'https://soulapi.quwanzhi.com'
|
||||
const STORAGE_KEY = 'apiBaseUrl'
|
||||
const POSITION_KEY = 'envSwitchPosition'
|
||||
|
||||
const URL_OPTIONS = [
|
||||
{ label: '生产', url: PRODUCTION_URL },
|
||||
{ label: '本地', url: 'http://localhost:8080' },
|
||||
{ label: '测试', url: 'https://souldev.quwanzhi.com' },
|
||||
]
|
||||
|
||||
Component({
|
||||
data: {
|
||||
visible: false,
|
||||
x: 20,
|
||||
y: 120,
|
||||
currentLabel: '生产',
|
||||
areaWidth: 375,
|
||||
areaHeight: 812,
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
attached() {
|
||||
try {
|
||||
const accountInfo = wx.getAccountInfoSync?.()
|
||||
const envVersion = accountInfo?.miniProgram?.envVersion || 'release'
|
||||
if (envVersion === 'release') {
|
||||
return
|
||||
}
|
||||
const sys = wx.getSystemInfoSync?.() || {}
|
||||
const areaWidth = sys.windowWidth || 375
|
||||
const areaHeight = sys.windowHeight || 812
|
||||
const saved = wx.getStorageSync(POSITION_KEY)
|
||||
const pos = saved ? JSON.parse(saved) : { x: 20, y: 120 }
|
||||
// 与 app.js 一致:storage 优先,否则用 globalData(已按 env 自动切换)
|
||||
const current = wx.getStorageSync(STORAGE_KEY) || getApp().globalData?.baseUrl || PRODUCTION_URL
|
||||
const opt = URL_OPTIONS.find(o => o.url === current) || URL_OPTIONS[0]
|
||||
this.setData({
|
||||
visible: true,
|
||||
x: pos.x ?? 20,
|
||||
y: pos.y ?? 120,
|
||||
currentLabel: opt.label,
|
||||
areaWidth,
|
||||
areaHeight,
|
||||
})
|
||||
} catch (_) {
|
||||
this.setData({ visible: false })
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onTap() {
|
||||
const items = URL_OPTIONS.map(o => o.label)
|
||||
const current = wx.getStorageSync(STORAGE_KEY) || PRODUCTION_URL
|
||||
const idx = URL_OPTIONS.findIndex(o => o.url === current)
|
||||
wx.showActionSheet({
|
||||
itemList: items,
|
||||
success: (res) => {
|
||||
const opt = URL_OPTIONS[res.tapIndex]
|
||||
wx.setStorageSync(STORAGE_KEY, opt.url)
|
||||
const app = getApp()
|
||||
if (app && app.globalData) {
|
||||
app.globalData.baseUrl = opt.url
|
||||
}
|
||||
this.setData({ currentLabel: opt.label })
|
||||
wx.showToast({ title: `已切到${opt.label}`, icon: 'none', duration: 1500 })
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
onMovableChange(e) {
|
||||
const { x, y } = e.detail
|
||||
if (typeof x === 'number' && typeof y === 'number') {
|
||||
wx.setStorageSync(POSITION_KEY, JSON.stringify({ x, y }))
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"component": true
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<movable-area wx:if="{{visible}}" class="env-area" style="width:{{areaWidth}}px;height:{{areaHeight}}px;">
|
||||
<movable-view
|
||||
class="env-btn"
|
||||
direction="all"
|
||||
inertia
|
||||
x="{{x}}"
|
||||
y="{{y}}"
|
||||
bindchange="onMovableChange"
|
||||
bindtap="onTap"
|
||||
>
|
||||
<view class="env-btn-inner">{{currentLabel}}</view>
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
@@ -1,30 +0,0 @@
|
||||
.env-area {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.env-btn {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.env-btn-inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
box-shadow: 0 4rpx 12rpx rgba(34, 197, 94, 0.4);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* 登录后若仍为默认头像/昵称,在此修改;仅头像与昵称两项
|
||||
*/
|
||||
const app = getApp()
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -14,15 +15,21 @@ Page({
|
||||
nicknameInputFocus: false,
|
||||
/** 规则引擎传入:avatar | nickname,用于高亮对应区块 */
|
||||
uiFocus: '',
|
||||
fromNewUser: false,
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 })
|
||||
const fromNewUser = String(options.from || '').toLowerCase() === 'new_user'
|
||||
const focus = String(options.focus || '').toLowerCase()
|
||||
if (focus === 'avatar' || focus === 'nickname') {
|
||||
this.setData({ uiFocus: focus })
|
||||
}
|
||||
this.setData({ fromNewUser })
|
||||
this.loadFromUser()
|
||||
if (fromNewUser) {
|
||||
trackClick('avatar_nickname', 'page_view', '新注册引导页')
|
||||
}
|
||||
if (focus === 'nickname') {
|
||||
setTimeout(() => {
|
||||
if (typeof wx.requirePrivacyAuthorize === 'function') {
|
||||
@@ -92,6 +99,7 @@ Page({
|
||||
async onChooseAvatar(e) {
|
||||
const tempAvatarUrl = e.detail?.avatarUrl
|
||||
if (!tempAvatarUrl) return
|
||||
trackClick('avatar_nickname', 'btn_click', '选择头像')
|
||||
await this.uploadAndSaveAvatar(tempAvatarUrl)
|
||||
},
|
||||
|
||||
@@ -132,6 +140,9 @@ Page({
|
||||
}
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: '头像已更新', icon: 'success' })
|
||||
if (this.data.fromNewUser) {
|
||||
trackClick('avatar_nickname', 'form_step_done', '头像更新完成')
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: e.message || '上传失败', icon: 'none' })
|
||||
@@ -150,6 +161,7 @@ Page({
|
||||
wx.showToast({ title: '请输入昵称', icon: 'none' })
|
||||
return
|
||||
}
|
||||
trackClick('avatar_nickname', 'btn_click', '完成保存')
|
||||
this.setData({ saving: true })
|
||||
try {
|
||||
await app.request({
|
||||
@@ -162,6 +174,13 @@ Page({
|
||||
if (avatar) app.globalData.userInfo.avatar = avatar
|
||||
wx.setStorageSync('userInfo', app.globalData.userInfo)
|
||||
}
|
||||
if (this.data.fromNewUser) {
|
||||
wx.setStorageSync('new_user_guide_done_at', Date.now())
|
||||
trackClick('avatar_nickname', 'form_submit', '新注册引导完成', {
|
||||
hasAvatar: !!avatar,
|
||||
nicknameLen: nickname.length,
|
||||
})
|
||||
}
|
||||
wx.showToast({ title: '保存成功', icon: 'success' })
|
||||
setTimeout(() => getApp().goBackOrToHome(), 800)
|
||||
} catch (e) {
|
||||
@@ -171,6 +190,7 @@ Page({
|
||||
},
|
||||
|
||||
goToFullProfile() {
|
||||
trackClick('avatar_nickname', 'nav_click', '编辑完整档案')
|
||||
wx.navigateTo({ url: '/pages/profile-edit/profile-edit' })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
<view class="content">
|
||||
<view class="guide-card">
|
||||
<icon name="handshake" size="64" color="#00CED1" customClass="guide-icon"></icon>
|
||||
<text class="guide-title">设置对外展示信息</text>
|
||||
<text class="guide-title">{{fromNewUser ? '欢迎加入,先完成基础信息' : '设置对外展示信息'}}</text>
|
||||
<text class="guide-badge" wx:if="{{fromNewUser}}">新用户引导</text>
|
||||
<text class="guide-desc" wx:if="{{uiFocus === 'avatar'}}">请先换一张清晰头像,伙伴更容易认出你。</text>
|
||||
<text class="guide-desc" wx:elif="{{uiFocus === 'nickname'}}">请改一个真实好记的昵称,方便伙伴称呼你。</text>
|
||||
<text class="guide-desc" wx:else>头像与昵称会出现在名片与匹配卡片上,方便伙伴认出你。</text>
|
||||
<text class="guide-desc guide-desc-sub" wx:if="{{fromNewUser}}">完成后可继续编辑完整档案(手机号、行业、MBTI 等)。</text>
|
||||
</view>
|
||||
|
||||
<!-- 头像:点击直接弹出微信原生选择器;头像与文字水平对齐 -->
|
||||
|
||||
@@ -64,11 +64,25 @@
|
||||
color: #5EEAD4;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.guide-badge {
|
||||
margin-bottom: 10rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
font-size: 20rpx;
|
||||
color: #22d3ee;
|
||||
border-radius: 999rpx;
|
||||
border: 1rpx solid rgba(34, 211, 238, 0.4);
|
||||
background: rgba(34, 211, 238, 0.1);
|
||||
}
|
||||
.guide-desc {
|
||||
font-size: 26rpx;
|
||||
color: rgba(148, 163, 184, 0.95);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.guide-desc-sub {
|
||||
margin-top: 8rpx;
|
||||
color: rgba(148, 163, 184, 0.85);
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
|
||||
@@ -54,7 +54,8 @@ Page({
|
||||
|
||||
// mp_config.mpUi.chaptersPage
|
||||
chaptersBookTitle: '一场SOUL的创业实验场',
|
||||
chaptersBookSubtitle: '来自Soul派对房的真实商业故事'
|
||||
chaptersBookSubtitle: '来自Soul派对房的真实商业故事',
|
||||
chaptersNewBadgeText: 'NEW'
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -71,13 +72,20 @@ Page({
|
||||
|
||||
_applyChaptersMpUi() {
|
||||
const c = app.globalData.configCache?.mpConfig?.mpUi?.chaptersPage || {}
|
||||
const h = app.globalData.configCache?.mpConfig?.mpUi?.homePage || {}
|
||||
const newBadgeText = String(c.newBadgeText || c.sectionNewBadgeText || h.latestSectionTitle || 'NEW').trim() || 'NEW'
|
||||
this.setData({
|
||||
chaptersBookTitle: String(c.bookTitle || '一场SOUL的创业实验场').trim() || '一场SOUL的创业实验场',
|
||||
chaptersBookSubtitle: String(c.bookSubtitle || '来自Soul派对房的真实商业故事').trim() ||
|
||||
'来自Soul派对房的真实商业故事'
|
||||
'来自Soul派对房的真实商业故事',
|
||||
chaptersNewBadgeText: newBadgeText
|
||||
})
|
||||
},
|
||||
|
||||
_normalizeBadgeText(v) {
|
||||
return String(v || '').trim().slice(0, 8)
|
||||
},
|
||||
|
||||
async loadFeatureConfig() {
|
||||
try {
|
||||
if (app.globalData.features && typeof app.globalData.features.searchEnabled === 'boolean') {
|
||||
@@ -122,10 +130,14 @@ Page({
|
||||
let icon = String(p.icon || '').trim()
|
||||
if (icon && !isSafeImageSrc(icon)) icon = ''
|
||||
const iconEmoji = icon ? '' : partEmojiForBodyIndex(idx)
|
||||
const partBadgeText = this._normalizeBadgeText(
|
||||
p.badgeText || p.badge_text || p.partBadgeText || p.part_badge_text
|
||||
)
|
||||
return {
|
||||
id: p.id,
|
||||
icon,
|
||||
iconEmoji,
|
||||
iconText: partBadgeText,
|
||||
title: p.title,
|
||||
subtitle: p.subtitle || '',
|
||||
chapterCount: p.chapterCount || 0,
|
||||
@@ -176,6 +188,9 @@ Page({
|
||||
isFree: r.isFree === true || (r.price !== undefined && r.price === 0),
|
||||
price: r.price ?? 1,
|
||||
isNew: r.isNew === true || r.is_new === true,
|
||||
newBadgeText: this._normalizeBadgeText(
|
||||
r.newBadgeText || r.new_badge_text || r.sectionBadgeText || r.section_badge_text || r.badgeText || r.badge_text
|
||||
),
|
||||
isPremium
|
||||
})
|
||||
})
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<view class="part-header" bindtap="togglePart" data-id="{{item.id}}">
|
||||
<view class="part-left">
|
||||
<image wx:if="{{item.icon}}" class="part-icon-img" src="{{item.icon}}" mode="aspectFill"/>
|
||||
<view wx:elif="{{item.iconText}}" class="part-icon part-icon-text">{{item.iconText}}</view>
|
||||
<view wx:elif="{{item.iconEmoji}}" class="part-icon part-icon-emoji">{{item.iconEmoji}}</view>
|
||||
<view wx:else class="part-icon">{{item.title[0] || '篇'}}</view>
|
||||
<view class="part-info">
|
||||
@@ -101,7 +102,7 @@
|
||||
<icon wx:else name="lock" size="24" color="rgba(255,255,255,0.3)" customClass="section-lock lock-closed"></icon>
|
||||
</view>
|
||||
<text class="section-title {{section.isFree || isVip || (!section.isPremium && hasFullBook) || purchasedSections.indexOf(section.id) > -1 ? '' : 'text-muted'}}">{{section.id}} {{section.title}}</text>
|
||||
<text wx:if="{{section.isNew}}" class="tag tag-new">NEW</text>
|
||||
<text wx:if="{{section.isNew || section.newBadgeText}}" class="tag tag-new">{{section.newBadgeText || chaptersNewBadgeText}}</text>
|
||||
</view>
|
||||
<view class="section-right">
|
||||
<text wx:if="{{section.isFree}}" class="tag tag-free">免费</text>
|
||||
|
||||
@@ -380,6 +380,13 @@
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.part-icon-text {
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.part-subtitle {
|
||||
font-size: 20rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* 点头像:登录后依次校验本人头像(非默认)、微信号、绑定手机号,再弹「链接「昵称」」;有 ckbLeadToken 走人物获客计划,否则走全局留资
|
||||
*/
|
||||
const app = getApp()
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
const { isSafeImageSrc } = require('../../utils/imageUrl.js')
|
||||
const { resolveAvatarWithMbti } = require('../../utils/mbtiAvatar.js')
|
||||
@@ -334,45 +335,13 @@ Page({
|
||||
/** 无人物 token 时:全局留资,便于运营侧主动加好友并协助链接该会员 */
|
||||
async _doGlobalMemberLeadSubmit(member) {
|
||||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) return
|
||||
const myUserId = app.globalData.userInfo.id
|
||||
let { phone, wechatId } = await this._resolveLeadPhoneWechat(myUserId)
|
||||
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,
|
||||
targetNickname: '',
|
||||
targetMemberId: member.id || undefined,
|
||||
targetMemberName: (member.name || '').trim() || undefined,
|
||||
source: 'member_detail_global',
|
||||
}
|
||||
})
|
||||
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, {
|
||||
targetMemberId: String(member.id || ''),
|
||||
targetMemberName: (member.name || '').trim(),
|
||||
targetNickname: '',
|
||||
source: 'member_detail_global',
|
||||
phoneModalContent: '请填写手机号(必填),便于工作人员联系您、协助链接该超级个体。',
|
||||
})
|
||||
},
|
||||
|
||||
async _resolveLeadPhoneWechat(myUserId) {
|
||||
@@ -390,58 +359,16 @@ Page({
|
||||
return { phone, wechatId }
|
||||
},
|
||||
|
||||
/** 与 read 页 _doMentionAddFriend 一致:targetUserId = Person.token;可选带超级个体 userId 写入留资 params */
|
||||
/** targetUserId = Person.token;可选带超级个体 id/name 写入留资 params(与 read 页 @ 同 soulBridge) */
|
||||
async _doCkbLeadSubmit(targetUserId, targetNickname, targetMemberId, targetMemberName) {
|
||||
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, wechatId } = await this._resolveLeadPhoneWechat(myUserId)
|
||||
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,
|
||||
targetMemberId: targetMemberId || undefined,
|
||||
targetMemberName: targetMemberName || 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,
|
||||
targetMemberId: targetMemberId || undefined,
|
||||
targetMemberName: targetMemberName || undefined,
|
||||
source: 'member_detail_avatar',
|
||||
phoneModalContent: '请填写手机号(必填),便于对方通过获客计划联系您。',
|
||||
})
|
||||
},
|
||||
|
||||
_ensureUnlockedForLink(field) {
|
||||
|
||||
@@ -1054,7 +1054,17 @@ Page({
|
||||
this.loadWalletBalance()
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: e.message || '提现失败', icon: 'none' })
|
||||
const resp = e && e.response
|
||||
if (resp && (resp.needBind || resp.needBindWechat)) {
|
||||
wx.showModal({
|
||||
title: resp.needBindWechat ? '请先绑定微信号' : '需要绑定微信',
|
||||
content: resp.needBindWechat ? '请到「设置」中绑定微信号后再提现,便于到账核对。' : '请先在设置中绑定微信账号后再提现',
|
||||
confirmText: '去绑定',
|
||||
success: (r) => { if (r.confirm) wx.navigateTo({ url: '/pages/settings/settings' }) }
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: (e && e.message) || '提现失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -140,6 +140,15 @@
|
||||
.save-btn[disabled] { opacity: 0.6; }
|
||||
.bottom-space { height: 120rpx; }
|
||||
|
||||
/* 分享图绘制用 canvas:仅用于离屏生成,不在页面可见 */
|
||||
.share-card-canvas {
|
||||
position: fixed;
|
||||
left: -9999px;
|
||||
top: -9999px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 昵称提示文案 */
|
||||
.input-tip {
|
||||
margin-top: 8rpx;
|
||||
@@ -234,93 +243,7 @@
|
||||
color: #9CA3AF;
|
||||
}
|
||||
|
||||
/* 昵称隐私弹窗 */
|
||||
.privacy-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.privacy-modal {
|
||||
width: 560rpx;
|
||||
padding: 48rpx 40rpx;
|
||||
background: #1E293B;
|
||||
border-radius: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.privacy-modal .privacy-title { font-size: 34rpx; font-weight: 600; color: #fff; margin-bottom: 24rpx; }
|
||||
.privacy-modal .privacy-desc { font-size: 28rpx; color: #94A3B8; line-height: 1.6; margin-bottom: 40rpx; }
|
||||
.privacy-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background: #5EEAD4;
|
||||
color: #0F172A;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 44rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 隐私授权弹窗 */
|
||||
.privacy-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.privacy-modal {
|
||||
width: 580rpx;
|
||||
background: #1E293B;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx 32rpx 32rpx;
|
||||
}
|
||||
.privacy-modal-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #F8FAFC;
|
||||
margin-bottom: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.privacy-modal-desc {
|
||||
font-size: 28rpx;
|
||||
color: #94A3B8;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
.privacy-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #5EEAD4;
|
||||
color: #0F172A;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 44rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.privacy-btn:last-of-type {
|
||||
margin-bottom: 0;
|
||||
background: transparent;
|
||||
color: #94A3B8;
|
||||
border: 2rpx solid #475569;
|
||||
}
|
||||
|
||||
/* 昵称隐私授权弹窗(解决 errno:104) */
|
||||
/* 昵称隐私授权弹窗(单一定义,避免样式冲突) */
|
||||
.privacy-mask {
|
||||
position: fixed; inset: 0; background: rgba(0,0,0,0.7); z-index: 9999;
|
||||
display: flex; align-items: center; justify-content: center; padding: 48rpx;
|
||||
|
||||
@@ -19,6 +19,7 @@ const { parseScene } = require('../../utils/scene.js')
|
||||
const contentParser = require('../../utils/contentParser.js')
|
||||
const { trackClick } = require('../../utils/trackClick')
|
||||
const { checkAndExecute } = require('../../utils/ruleEngine')
|
||||
const soulBridge = require('../../utils/soulBridge.js')
|
||||
|
||||
const app = getApp()
|
||||
|
||||
@@ -729,71 +730,14 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 边界:未登录→去登录;无手机/微信号→去资料编辑;重复同一人→本地 key 去重
|
||||
// 正文 @:统一走 soulBridge(登录/手机号校验/提交与错误提示一处维护)
|
||||
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(getApp(), {
|
||||
targetUserId,
|
||||
targetNickname,
|
||||
source: 'article_mention',
|
||||
phoneModalContent: '请填写手机号(必填),便于对方联系您。',
|
||||
})
|
||||
},
|
||||
|
||||
// 分享弹窗
|
||||
@@ -1245,7 +1189,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 })
|
||||
@@ -1315,8 +1259,8 @@ Page({
|
||||
? '《一场Soul的创业实验》全书'
|
||||
: `章节${sectionId}-${sectionTitle.length > 20 ? sectionTitle.slice(0, 20) + '...' : sectionTitle}`
|
||||
|
||||
// 邀请码:谁邀请了我(从落地页 ref 或 storage 带入),会写入订单 referrer_id / referral_code 便于分销与对账
|
||||
const referralCode = wx.getStorageSync('referral_code') || ''
|
||||
// 邀请码:与 VIP/钱包一致,优先 storage 落地 ref,否则回落本人推荐码便于自购归因
|
||||
const referralCode = soulBridge.getReferralCodeForPay(app)
|
||||
const res = await app.request('/api/miniprogram/pay', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
|
||||
@@ -677,7 +677,7 @@ Page({
|
||||
wx.navigateTo({ url: '/pages/withdraw-records/withdraw-records' })
|
||||
},
|
||||
|
||||
// 执行提现
|
||||
// 执行提现(success:false 时 app.request 会 reject 并挂 e.response,需 catch 里处理 needBindWechat)
|
||||
async doWithdraw(amount) {
|
||||
wx.showLoading({ title: '提现中...' })
|
||||
|
||||
@@ -706,24 +706,23 @@ Page({
|
||||
|
||||
// 刷新数据(此时待审核金额会增加,可提现金额会减少)
|
||||
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 })
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
console.error('[Referral] 提现失败:', e)
|
||||
wx.showToast({ title: '提现失败,请重试', icon: 'none' })
|
||||
const resp = e && e.response
|
||||
if (resp && (resp.needBind || resp.needBindWechat)) {
|
||||
wx.showModal({
|
||||
title: resp.needBindWechat ? '请先绑定微信号' : '需要绑定微信',
|
||||
content: resp.needBindWechat ? '请到「设置」中绑定微信号后再提现,便于到账核对。' : '请先在设置中绑定微信账号后再提现',
|
||||
confirmText: '去绑定',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) wx.navigateTo({ url: '/pages/settings/settings' })
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: (e && e.message) || '提现失败,请重试', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -54,8 +54,14 @@ function stripTrailingAtForMention(before) {
|
||||
* 将一个 HTML block 字符串解析为 segments 数组
|
||||
* 处理三种内联元素:mention / linkTag(span) / linkTag(a) / img
|
||||
*/
|
||||
function parseBlockToSegments(block) {
|
||||
function parseBlockToSegments(block, config) {
|
||||
const segs = []
|
||||
const normalize = s => (s || '').trim().toLowerCase()
|
||||
const personTokenSet = new Set()
|
||||
for (const p of ((config && config.persons) || [])) {
|
||||
const token = normalize((p && p.token) || '')
|
||||
if (token) personTokenSet.add(token)
|
||||
}
|
||||
// 合并匹配所有内联元素
|
||||
const tokenRe = /<span[^>]*data-type="mention"[^>]*>[\s\S]*?<\/span>|<span[^>]*data-type="linkTag"[^>]*>[\s\S]*?<\/span>|<a[^>]*href="([^"]*)"[^>]*>(#[^<]*)<\/a>|<img[^>]*\/?>/gi
|
||||
let lastEnd = 0
|
||||
@@ -78,8 +84,12 @@ function parseBlockToSegments(block) {
|
||||
const userId = idMatch ? idMatch[1].trim() : ''
|
||||
let nickname = labelMatch ? labelMatch[1] : innerText.replace(/^[@@]\s*/, '')
|
||||
nickname = cleanMentionNickname((nickname || '').trim())
|
||||
if (userId || nickname) {
|
||||
const userExists = !!normalize(userId) && personTokenSet.has(normalize(userId))
|
||||
if (userExists && nickname) {
|
||||
segs.push({ type: 'mention', userId, nickname, mentionDisplay: '@' + nickname })
|
||||
} else if (nickname) {
|
||||
// 被 @ 人物不存在时降级为普通文本,保持“静态 @某人”展示
|
||||
segs.push({ type: 'text', text: '@' + nickname })
|
||||
}
|
||||
|
||||
} else if (/data-type="linkTag"/i.test(tag)) {
|
||||
@@ -155,7 +165,7 @@ function parseHtmlToSegments(html, config) {
|
||||
for (const block of blocks) {
|
||||
if (!block.trim()) continue
|
||||
|
||||
let blockSegs = parseBlockToSegments(block)
|
||||
let blockSegs = parseBlockToSegments(block, config)
|
||||
if (!blockSegs.length) continue
|
||||
|
||||
// 纯图片行独立成段
|
||||
|
||||
@@ -59,16 +59,20 @@ function syncOrderStatusQuery(app, orderSn) {
|
||||
/**
|
||||
* 提交存客宝 lead(与阅读页 @、会员详情点头像同接口)
|
||||
* @param {object} app getApp()
|
||||
* @param {{ targetUserId: string, targetNickname?: string, source: string, phoneModalContent?: string }} opts
|
||||
* @param {{ targetUserId?: string, targetNickname?: string, targetMemberId?: string, targetMemberName?: string, source: string, phoneModalContent?: string }} opts
|
||||
* @returns {Promise<boolean>} 是否提交成功
|
||||
*/
|
||||
async function submitCkbLead(app, opts) {
|
||||
const targetUserId = (opts && opts.targetUserId) || ''
|
||||
const targetNickname = ((opts && opts.targetNickname) || 'TA').trim() || 'TA'
|
||||
const targetUserId = ((opts && opts.targetUserId) || '').trim()
|
||||
const targetMemberId = ((opts && opts.targetMemberId) || '').trim()
|
||||
let targetNickname = (opts && opts.targetNickname != null) ? String(opts.targetNickname).trim() : ''
|
||||
if (targetUserId && !targetNickname) targetNickname = 'TA'
|
||||
const targetMemberName = ((opts && opts.targetMemberName) || '').trim()
|
||||
const source = (opts && opts.source) || 'article_mention'
|
||||
const phoneModalContent = (opts && opts.phoneModalContent) || '请先填写手机号(必填),以便对方联系您'
|
||||
|
||||
if (!targetUserId) return false
|
||||
// 文章 @ 为 token;会员详情无 token 时用 targetMemberId 走全局获客计划(与后端 CKBLead 一致)
|
||||
if (!targetUserId && !targetMemberId) return false
|
||||
|
||||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) {
|
||||
return await new Promise((resolve) => {
|
||||
@@ -124,8 +128,10 @@ async function submitCkbLead(app, opts) {
|
||||
phone: phone || undefined,
|
||||
wechatId: wechatId || undefined,
|
||||
name: (app.globalData.userInfo.nickname || '').trim() || undefined,
|
||||
targetUserId,
|
||||
targetNickname: targetNickname || undefined,
|
||||
targetUserId: targetUserId || undefined,
|
||||
targetNickname: targetNickname !== '' ? targetNickname : undefined,
|
||||
targetMemberId: targetMemberId || undefined,
|
||||
targetMemberName: targetMemberName || undefined,
|
||||
source
|
||||
}
|
||||
})
|
||||
@@ -141,7 +147,9 @@ async function submitCkbLead(app, opts) {
|
||||
return false
|
||||
} catch (e) {
|
||||
wx.hideLoading()
|
||||
wx.showToast({ title: (e && e.message) || '提交失败', icon: 'none' })
|
||||
const resp = e && e.response
|
||||
const hint = (resp && (resp.message || resp.error)) || (e && e.message) || '提交失败'
|
||||
wx.showToast({ title: String(hint), icon: 'none' })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user