/** * 卡若创业派对 - 超级个体/会员详情页 * 接口:优先 /api/miniprogram/vip/members?id=xx(VIP),回退 /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 } } })