- miniprogram: reading-records、imageUrl/mpNavigate、多页资料与 VIP 展示调整 - soul-admin: Users/Settings/UserDetailModal、dist 构建产物更新 - soul-api: user/vip/referral/ckb/db、MBTI 头像管理、user_rule_completion、迁移 SQL - .cursor: karuo-party 与飞书文档;.gitignore 忽略 .tmp_skill_bundle Made-with: Cursor
623 lines
25 KiB
JavaScript
623 lines
25 KiB
JavaScript
/**
|
||
* 卡若创业派对 - 超级个体/会员详情页
|
||
* 接口:优先 /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
|
||
* 点头像:登录后依次校验本人头像(非默认)、微信号、绑定手机号,再弹「链接「昵称」」;有 ckbLeadToken 走人物获客计划,否则走全局留资
|
||
*/
|
||
const app = getApp()
|
||
const { trackClick } = require('../../utils/trackClick')
|
||
const { isSafeImageSrc } = require('../../utils/imageUrl.js')
|
||
|
||
Page({
|
||
data: { statusBarHeight: 44, navBarTotalPx: 88, member: null, loading: true, isOwnProfile: false },
|
||
|
||
onLoad(options) {
|
||
wx.showShareMenu({ withShareTimeline: true })
|
||
const sb = app.globalData.statusBarHeight || 44
|
||
const myId = app.globalData.userInfo?.id
|
||
const isOwnProfile = !!(options.id && myId && String(options.id) === String(myId))
|
||
this.setData({ statusBarHeight: sb, navBarTotalPx: sb + 44, isOwnProfile })
|
||
if (options.id) this.loadMember(options.id)
|
||
},
|
||
|
||
/** 本人名片:去完整编辑资料(单页) */
|
||
goMyProfileEdit() {
|
||
wx.navigateTo({ url: '/pages/profile-edit/profile-edit?full=1' })
|
||
},
|
||
|
||
async loadMember(id) {
|
||
const myId = app.globalData.userInfo?.id
|
||
const isOwn = !!(myId && id != null && String(id) === String(myId))
|
||
if (isOwn && app.globalData.isLoggedIn && myId) {
|
||
try {
|
||
const res = await app.request({
|
||
url: `/api/miniprogram/user/profile?userId=${encodeURIComponent(String(id))}`,
|
||
silent: true
|
||
})
|
||
if (res?.success && res.data) {
|
||
const d = res.data
|
||
this.setData({
|
||
member: this.enrichAndFormat({
|
||
id: d.id,
|
||
nickname: d.nickname,
|
||
name: d.nickname,
|
||
avatar: d.avatar,
|
||
phone: d.phone,
|
||
wechatId: d.wechatId || d.wechat_id,
|
||
isVip: !!app.globalData.isVip,
|
||
mbti: d.mbti,
|
||
region: d.region,
|
||
industry: d.industry,
|
||
position: d.position,
|
||
businessScale: d.businessScale || d.business_scale,
|
||
skills: d.skills,
|
||
storyBestMonth: d.storyBestMonth || d.story_best_month,
|
||
storyAchievement: d.storyAchievement || d.story_achievement,
|
||
storyTurning: d.storyTurning || d.story_turning,
|
||
helpOffer: d.helpOffer || d.help_offer,
|
||
helpNeed: d.helpNeed || d.help_need,
|
||
projectIntro: d.projectIntro || d.project_intro,
|
||
ckbLeadToken: d.ckbLeadToken || d.ckb_lead_token
|
||
}),
|
||
loading: false
|
||
})
|
||
return
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
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 rawAv = raw.avatar || raw.vipAvatar || raw.vip_avatar || ''
|
||
const merged = {
|
||
id: raw.id,
|
||
name: raw.nickname || raw.name || raw.vipName || raw.vip_name || '创业者',
|
||
avatar: isSafeImageSrc(rawAv) ? String(rawAv).trim() : '',
|
||
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
|
||
},
|
||
|
||
/** 链接前:头像需非空且非默认图;微信号需已填写(与 app._needsAvatarNickname 中头像规则一致) */
|
||
_hasCustomAvatarForLink(u) {
|
||
const avatar = (u && (u.avatar || u.avatarUrl) || '').trim()
|
||
return !!avatar && !avatar.includes('default')
|
||
},
|
||
|
||
_hasWechatFilledForLink(u) {
|
||
const w = (u && (u.wechatId || u.wechat_id) || wx.getStorageSync('user_wechat') || '').trim()
|
||
return w.length > 0
|
||
},
|
||
|
||
/** 拉取最新 profile 写回 globalData,返回合并后的访客资料片段 */
|
||
async _refreshVisitorProfileForLink() {
|
||
const base = app.globalData.userInfo
|
||
if (!base?.id) return base || {}
|
||
try {
|
||
const profileRes = await app.request({ url: `/api/miniprogram/user/profile?userId=${base.id}`, silent: true })
|
||
if (profileRes?.success && profileRes.data) {
|
||
const d = profileRes.data
|
||
const updated = { ...app.globalData.userInfo }
|
||
if (d.avatar != null && String(d.avatar).trim()) updated.avatar = String(d.avatar).trim()
|
||
if (d.wechatId != null) updated.wechatId = d.wechatId
|
||
if (d.wechat_id != null) updated.wechat_id = d.wechat_id
|
||
app.globalData.userInfo = updated
|
||
wx.setStorageSync('userInfo', updated)
|
||
if (d.wechatId) wx.setStorageSync('user_wechat', String(d.wechatId).trim())
|
||
return updated
|
||
}
|
||
} catch (e) {}
|
||
return base
|
||
},
|
||
|
||
async _ensureVisitorReadyForMemberLink() {
|
||
const u = await this._refreshVisitorProfileForLink()
|
||
const avatarOk = this._hasCustomAvatarForLink(u)
|
||
const wechatOk = this._hasWechatFilledForLink(u)
|
||
if (avatarOk && wechatOk) return true
|
||
const miss = []
|
||
if (!avatarOk) miss.push('头像')
|
||
if (!wechatOk) miss.push('微信号')
|
||
wx.showModal({
|
||
title: '补全本人档案',
|
||
content: `链接前请补全本人${miss.join('与')},便于对方识别与安全对接。`,
|
||
confirmText: '去填写',
|
||
cancelText: '取消',
|
||
success: (r) => { if (r.confirm) wx.navigateTo({ url: '/pages/profile-edit/profile-edit' }) }
|
||
})
|
||
return false
|
||
},
|
||
|
||
/** 链接前:必须已绑定大陆手机号(与留资接口校验一致) */
|
||
async _ensurePhoneBoundForLink(myUserId) {
|
||
const { phone } = await this._resolveLeadPhoneWechat(myUserId)
|
||
if (phone && /^1[3-9]\d{9}$/.test(phone)) return true
|
||
wx.showModal({
|
||
title: '请先绑定手机号',
|
||
content: '链接对方前需绑定本人手机号,便于跟进与对接。',
|
||
confirmText: '去绑定',
|
||
cancelText: '取消',
|
||
success: (r) => { if (r.confirm) wx.navigateTo({ url: '/pages/profile-edit/profile-edit' }) }
|
||
})
|
||
return false
|
||
},
|
||
|
||
/**
|
||
* 点头像:登录 → 头像+微信号 → 手机号 均校验通过后弹窗说明;确认后 POST ckb/lead。
|
||
* 有 ckbLeadToken 走人物计划;无 token 走全局留资。对方已公开联系方式时可取消后在下方自行添加。
|
||
*/
|
||
async startLinkFlow() {
|
||
if (this.data.isOwnProfile) return
|
||
const member = this.data.member
|
||
if (!member) return
|
||
const nickname = (member.name || 'TA').trim() || 'TA'
|
||
trackClick('member_detail', 'btn_click', '链接头像_' + (member.id || ''))
|
||
|
||
if (!app.globalData.isLoggedIn || !app.globalData.userInfo) {
|
||
wx.showModal({
|
||
title: `链接「${nickname}」`,
|
||
content: '请先登录后再发起链接。',
|
||
confirmText: '去登录',
|
||
cancelText: '取消',
|
||
success: (r) => { if (r.confirm) wx.switchTab({ url: '/pages/my/my' }) }
|
||
})
|
||
return
|
||
}
|
||
|
||
const myUserId = app.globalData.userInfo.id
|
||
wx.showLoading({ title: '请稍候', mask: true })
|
||
let profileOk = false
|
||
let phoneOk = false
|
||
try {
|
||
profileOk = await this._ensureVisitorReadyForMemberLink()
|
||
if (profileOk) phoneOk = await this._ensurePhoneBoundForLink(myUserId)
|
||
} finally {
|
||
wx.hideLoading()
|
||
}
|
||
if (!profileOk || !phoneOk) return
|
||
|
||
const leadTok = (member.ckbLeadToken || '').trim()
|
||
const content = leadTok
|
||
? `确定后提交联系方式,平台将按对方配置跟进;智能助手与人工协同协助对接。`
|
||
: `智能助手与人工会协同跟进,协助您对接「${nickname}」。\n\n若对方已公开手机或微信,可先点「取消」,在页面下方自行添加。`
|
||
|
||
wx.showModal({
|
||
title: `链接「${nickname}」`,
|
||
content,
|
||
confirmText: '确定链接',
|
||
cancelText: '取消',
|
||
success: (r) => {
|
||
if (!r.confirm) return
|
||
if (leadTok) this._doCkbLeadSubmit(leadTok, nickname, member.id, nickname)
|
||
else this._doGlobalMemberLeadSubmit(member)
|
||
}
|
||
})
|
||
},
|
||
|
||
/** 无人物 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' })
|
||
}
|
||
},
|
||
|
||
async _resolveLeadPhoneWechat(myUserId) {
|
||
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) {}
|
||
}
|
||
return { phone, wechatId }
|
||
},
|
||
|
||
/** 与 read 页 _doMentionAddFriend 一致:targetUserId = Person.token;可选带超级个体 userId 写入留资 params */
|
||
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' })
|
||
}
|
||
},
|
||
|
||
_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() },
|
||
|
||
/**
|
||
* 分享标题:姓名|MBTI(有则加)|擅长;无擅长时用个人故事或职业一行。总长控制避免微信卡片截断难看。
|
||
*/
|
||
_buildMemberShareTitle(maxLen = 56) {
|
||
const m = this.data.member
|
||
if (!m) return '卡若创业派对 · 超级个体'
|
||
|
||
const clip = (s, n) => {
|
||
if (!s) return ''
|
||
const t = String(s).replace(/\s+/g, ' ').trim()
|
||
return t.length <= n ? t : t.slice(0, n - 1) + '…'
|
||
}
|
||
|
||
const name = clip((m.name || '创业者').trim() || '创业者', 14)
|
||
const mbti = (m.mbti || '').trim()
|
||
const skills = (m.skills || '').trim()
|
||
const achievement = (m.achievement || '').trim()
|
||
const bestMonth = (m.bestMonth || '').trim()
|
||
const turning = (m.turningPoint || '').trim()
|
||
const story = achievement || bestMonth || turning || ''
|
||
const jobLine = [m.industry, m.position].filter(Boolean).join('·')
|
||
|
||
const sep = '|'
|
||
const nameSeg = name
|
||
const mbtiSeg = mbti ? clip(mbti, 8) : ''
|
||
const usedBase = nameSeg.length + (mbtiSeg ? sep.length + mbtiSeg.length : 0)
|
||
const willTail = !!(skills || story || jobLine || m.region)
|
||
const restBudget = Math.max(6, maxLen - usedBase - (willTail ? sep.length : 0))
|
||
|
||
let tail = ''
|
||
if (skills) tail = clip(skills, restBudget)
|
||
else if (story) tail = clip(story, restBudget)
|
||
else if (jobLine) tail = clip(jobLine, restBudget)
|
||
else if (m.region) tail = clip(m.region, restBudget)
|
||
|
||
let title = nameSeg
|
||
if (mbtiSeg) title += sep + mbtiSeg
|
||
if (tail) title += sep + tail
|
||
|
||
title = clip(title.replace(/\s+/g, ' '), maxLen)
|
||
if (!title || title.length < 3) title = clip(`${nameSeg}${sep}超级个体`, maxLen)
|
||
return title
|
||
},
|
||
|
||
onShareAppMessage() {
|
||
const ref = app.getMyReferralCode()
|
||
const id = this.data.member?.id
|
||
const title = this._buildMemberShareTitle(64)
|
||
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 m = this.data.member
|
||
const q = id ? (ref ? `id=${id}&ref=${ref}` : `id=${id}`) : (ref ? `ref=${ref}` : '')
|
||
const title = this._buildMemberShareTitle(56)
|
||
const res = { title, query: q }
|
||
if (m && m.avatar && /^https?:\/\//.test(String(m.avatar))) {
|
||
res.imageUrl = m.avatar
|
||
}
|
||
return res
|
||
}
|
||
})
|