Files
soul-yongping/miniprogram/pages/member-detail/member-detail.js
Alex-larget 28ad08da84 同步
2026-03-24 15:44:08 +08:00

340 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 卡若创业派对 - 超级个体/会员详情页
* 接口:优先 /api/miniprogram/vip/members?id=xxVIP回退 /api/miniprogram/users?id=xx任意用户
* 头像/昵称统一用用户资料nickname/avatar优先随「我的」修改实时生效
* mbti, region, industry, position, businessScale, skills,
* storyBestMonth→bestMonth, storyAchievement→achievement, storyTurning→turningPoint,
* helpOffer→canHelp, helpNeed→needHelp
* 点头像:若后台 persons.user_id 已绑定则带 ckbLeadToken走存客宝 CKBLead与阅读页 @ 一致)
*/
const app = getApp()
const soulBridge = require('../../utils/soulBridge.js')
Page({
data: { statusBarHeight: 44, navBarTotalPx: 88, member: null, loading: true },
onLoad(options) {
wx.showShareMenu({ withShareTimeline: true })
const sb = app.globalData.statusBarHeight || 44
this.setData({ statusBarHeight: sb, navBarTotalPx: sb + 44 })
if (options.id) this.loadMember(options.id)
},
async loadMember(id) {
try {
const res = await app.request({ url: `/api/miniprogram/vip/members?id=${id}`, silent: true })
if (res?.success && res.data) {
const d = Array.isArray(res.data) ? res.data[0] : res.data
if (d) { this.setData({ member: this.enrichAndFormat(d), loading: false }); return }
}
} catch (e) {}
try {
const dbRes = await app.request({ url: `/api/miniprogram/users?id=${id}`, silent: true })
if (dbRes?.success && dbRes.data) {
const u = Array.isArray(dbRes.data) ? dbRes.data[0] : dbRes.data
if (u) {
this.setData({ member: this.enrichAndFormat({
id: u.id, name: u.nickname || u.vipName || u.vip_name || '创业者',
avatar: u.avatar || u.vipAvatar || u.vip_avatar || '', isVip: !!(u.is_vip),
contactRaw: u.vipContact || u.vip_contact || u.phone || '',
wechatId: u.wechatId || u.wechat_id,
project: u.vipProject || u.vip_project || u.projectIntro || u.project_intro || '',
industry: u.industry, position: u.position, businessScale: u.businessScale || u.business_scale,
skills: u.skills, mbti: u.mbti, region: u.region,
storyBestMonth: u.storyBestMonth || u.story_best_month,
storyAchievement: u.storyAchievement || u.story_achievement,
storyTurning: u.storyTurning || u.story_turning,
helpOffer: u.helpOffer || u.help_offer,
helpNeed: u.helpNeed || u.help_need,
ckbLeadToken: u.ckbLeadToken || u.ckb_lead_token,
}), loading: false })
return
}
}
} catch (e) {}
this.setData({ loading: false })
},
// 将空值、「未填写」、纯空格均视为未填写(用于隐藏对应项)
_emptyIfPlaceholder(v) {
if (v == null || v === undefined) return ''
const s = String(v).trim()
return (s === '' || s === '未填写') ? '' : s
},
enrichAndFormat(raw) {
const e = (v) => this._emptyIfPlaceholder(v)
const merged = {
id: raw.id,
name: raw.nickname || raw.name || raw.vipName || raw.vip_name || '创业者',
avatar: raw.avatar || raw.vipAvatar || raw.vip_avatar || '',
isVip: !!(raw.isVip || raw.is_vip),
mbti: e(raw.mbti),
region: e(raw.region),
industry: e(raw.industry),
position: e(raw.position),
businessScale: e(raw.businessScale || raw.business_scale),
skills: e(raw.skills),
contactRaw: raw.contactRaw || raw.vipContact || raw.vip_contact || raw.phone || '',
wechatRaw: raw.wechatRaw || raw.wechatId || raw.wechat_id || '',
bestMonth: e(raw.bestMonth || raw.storyBestMonth || raw.story_best_month),
achievement: e(raw.achievement || raw.storyAchievement || raw.story_achievement),
turningPoint: e(raw.turningPoint || raw.storyTurning || raw.story_turning),
canHelp: e(raw.canHelp || raw.helpOffer || raw.help_offer),
needHelp: e(raw.needHelp || raw.helpNeed || raw.help_need),
project: e(raw.project || raw.vipProject || raw.vip_project || raw.projectIntro || raw.project_intro),
ckbLeadToken: String(raw.ckbLeadToken || raw.ckb_lead_token || '').trim()
}
const contact = merged.contactRaw || ''
const wechat = merged.wechatRaw || ''
const isMatched = (app.globalData.matchedUsers || []).includes(merged.id)
const unlockData = this._getUnlockData(merged.id)
merged.contactDisplay = contact ? (contact.slice(0, 3) + '****' + (contact.length > 7 ? contact.slice(-2) : '')) : ''
merged.contactUnlocked = isMatched || unlockData.contact
merged.contactFull = contact
merged.wechatDisplay = wechat ? (wechat.slice(0, 4) + '****' + (wechat.length > 8 ? wechat.slice(-3) : '')) : ''
merged.wechatUnlocked = isMatched || unlockData.wechat
merged.wechatFull = wechat
return merged
},
_getUnlockData(memberId) {
const userId = app.globalData.userInfo?.id
if (!userId || !memberId) return { contact: false, wechat: false }
try {
const raw = wx.getStorageSync('member_unlocks_' + userId)
if (Array.isArray(raw) && raw.includes(memberId)) {
return { contact: true, wechat: true }
}
const data = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {}
const member = data[memberId]
return {
contact: !!(member && member.contact),
wechat: !!(member && member.wechat)
}
} catch (e) { return { contact: false, wechat: false } }
},
_addUnlock(memberId, field) {
const userId = app.globalData.userInfo?.id
if (!userId || !memberId || !field) return
let obj = wx.getStorageSync('member_unlocks_' + userId)
if (Array.isArray(obj)) {
obj = obj.reduce((o, id) => { o[id] = { contact: true, wechat: true }; return o }, {})
}
obj = obj && typeof obj === 'object' ? obj : {}
if (!obj[memberId]) obj[memberId] = {}
obj[memberId][field] = true
wx.setStorageSync('member_unlocks_' + userId, obj)
},
_hasUsedFreeForMember(memberId) {
const d = this._getUnlockData(memberId)
return d.contact || d.wechat
},
/** VIP 或本会员首次免费:写入解锁;否则弹开通 VIP */
_tryFreeUnlock(member, field) {
const isVip = app.globalData.isVip
const usedFree = this._hasUsedFreeForMember(member.id)
if (isVip || !usedFree) {
this._addUnlock(member.id, field)
return true
}
wx.showModal({
title: '解锁' + (field === 'contact' ? '联系方式' : '微信号'),
content: '您的免费解锁次数已用完开通VIP会员¥1980/年)可无限解锁',
confirmText: '去开通',
cancelText: '取消',
success: (res) => { if (res.confirm) wx.navigateTo({ url: '/pages/vip/vip' }) }
})
return false
},
/**
* 点头像:有存客宝人物 token 时优先 POST /api/miniprogram/ckb/lead与阅读页 @ 同链路,匹配 persons.ckb_api_key 计划)
* 否则:解锁后复制微信/手机号并引导
*/
startLinkFlow() {
const member = this.data.member
if (!member) return
const leadTok = (member.ckbLeadToken || '').trim()
if (leadTok) {
const nickname = ((member.name || 'TA').trim() || 'TA')
wx.showModal({
title: '添加好友',
content: `是否通过获客计划联系 ${nickname}?提交后将按对方在存客宝后台配置的计划执行。`,
confirmText: '确定',
cancelText: '取消',
success: (res) => {
if (res.confirm) this._doCkbLeadSubmit(leadTok, nickname)
}
})
return
}
if (member.wechatRaw || member.wechatDisplay) {
if (!this._ensureUnlockedForLink('wechat')) return
const m = this.data.member
if (m.wechatFull) this._copyAndGuideWechat(m.wechatFull)
return
}
if (member.contactRaw || member.contactDisplay) {
if (!this._ensureUnlockedForLink('contact')) return
const m = this.data.member
if (m.contactFull) this._copyAndGuidePhone(m.contactFull)
return
}
wx.showToast({ title: '暂未公开联系方式', icon: 'none' })
},
/** 与阅读页 @mention 同链路soulBridge.submitCkbLead */
async _doCkbLeadSubmit(targetUserId, targetNickname) {
await soulBridge.submitCkbLead(app, {
targetUserId,
targetNickname,
source: 'member_detail_avatar',
phoneModalContent: '请先填写手机号(必填),以便对方通过获客计划联系您'
})
},
_ensureUnlockedForLink(field) {
const member = this.data.member
if (!member?.id || (field !== 'contact' && field !== 'wechat')) return false
if (field === 'wechat' && member.wechatUnlocked) return true
if (field === 'contact' && member.contactUnlocked) return true
if (!app.globalData.isLoggedIn) {
wx.showModal({
title: '需要登录',
content: field === 'wechat'
? '登录后可解锁并复制对方微信号,再按步骤去微信添加好友。'
: '登录后可解锁并复制对方手机号,便于添加好友或回拨。',
confirmText: '去登录',
cancelText: '取消',
success: (res) => { if (res.confirm) wx.switchTab({ url: '/pages/my/my' }) }
})
return false
}
const d = this._getUnlockData(member.id)
if ((field === 'wechat' && d.wechat) || (field === 'contact' && d.contact)) {
this.setData({ member: this.enrichAndFormat(member) })
return true
}
if (!this._tryFreeUnlock(member, field)) return false
this.setData({ member: this.enrichAndFormat(member) })
return true
},
_copyAndGuideWechat(wechatId) {
if (!wechatId) return
wx.setClipboardData({
data: String(wechatId),
success: () => {
wx.hideToast()
setTimeout(() => {
wx.hideToast()
wx.showModal({
title: '添加微信好友',
content: '微信号已复制。\n\n请打开微信 → 右上角「+」→ 添加朋友 → 粘贴搜索并添加。',
showCancel: false,
confirmText: '知道了'
})
}, 120)
},
fail: () => wx.showToast({ title: '复制失败', icon: 'none' })
})
},
_copyAndGuidePhone(phone) {
if (!phone) return
wx.setClipboardData({
data: String(phone),
success: () => {
wx.hideToast()
setTimeout(() => {
wx.hideToast()
wx.showModal({
title: '联系对方',
content: '手机号已复制。\n\n可打开微信「添加朋友」搜索手机号或使用手机拨号联系对方。',
showCancel: false,
confirmText: '知道了'
})
}, 120)
},
fail: () => wx.showToast({ title: '复制失败', icon: 'none' })
})
},
unlockField(e) {
const field = e.currentTarget.dataset.field
if (!field) return
const member = this.data.member
if (!member?.id || (field !== 'contact' && field !== 'wechat')) return
const isLoggedIn = app.globalData.isLoggedIn
if (!isLoggedIn) {
wx.showModal({
title: '需要登录',
content: '请先登录后再解锁超级个体联系方式',
confirmText: '去登录',
cancelText: '取消',
success: (res) => { if (res.confirm) wx.switchTab({ url: '/pages/my/my' }) }
})
return
}
const d = this._getUnlockData(member.id)
if (d[field]) return
if (this._tryFreeUnlock(member, field)) {
const m = this.enrichAndFormat(member)
this.setData({ member: m })
wx.showToast({ title: field === 'contact' ? '已解锁联系方式' : '已解锁微信号', icon: 'success' })
}
},
tapContactRow() {
const m = this.data.member
if (!m || !(m.contactRaw || m.contactDisplay)) return
if (m.contactUnlocked) this.copyContact()
else this.unlockField({ currentTarget: { dataset: { field: 'contact' } } })
},
tapWechatRow() {
const m = this.data.member
if (!m || !(m.wechatRaw || m.wechatDisplay)) return
if (m.wechatUnlocked) this.copyWechat()
else this.unlockField({ currentTarget: { dataset: { field: 'wechat' } } })
},
copyContact() {
const c = this.data.member?.contactFull
if (!c) return
wx.setClipboardData({ data: c, success: () => wx.showToast({ title: '已复制', icon: 'success' }) })
},
copyWechat() {
const w = this.data.member?.wechatFull
if (!w) return
wx.setClipboardData({ data: w, success: () => wx.showToast({ title: '已复制', icon: 'success' }) })
},
goToMatch() { wx.switchTab({ url: '/pages/match/match' }) },
goToVip() { wx.navigateTo({ url: '/pages/vip/vip' }) },
goBack() { getApp().goBackOrToHome() },
onShareAppMessage() {
const ref = app.getMyReferralCode()
const id = this.data.member?.id
return {
title: '卡若创业派对 - 创业者详情',
path: id && ref ? `/pages/member-detail/member-detail?id=${id}&ref=${ref}` : id ? `/pages/member-detail/member-detail?id=${id}` : ref ? `/pages/member-detail/member-detail?ref=${ref}` : '/pages/member-detail/member-detail'
}
},
onShareTimeline() {
const ref = app.getMyReferralCode()
const id = this.data.member?.id
const q = id ? (ref ? `id=${id}&ref=${ref}` : `id=${id}`) : (ref ? `ref=${ref}` : '')
return { title: '卡若创业派对 - 创业者详情', query: q }
}
})