初始提交:一场soul的创业实验-永平 网站与小程序
Made-with: Cursor
This commit is contained in:
767
miniprogram/pages/match/match.js
Normal file
767
miniprogram/pages/match/match.js
Normal file
@@ -0,0 +1,767 @@
|
||||
/**
|
||||
* Soul创业派对 - 找伙伴页
|
||||
* 按H5网页端完全重构
|
||||
* 开发: 卡若
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
|
||||
// 默认匹配类型配置
|
||||
// 找伙伴:真正的匹配功能,匹配数据库中的真实用户
|
||||
// 资源对接:需要登录+购买章节才能使用,填写2项信息(我能帮到你什么、我需要什么帮助)
|
||||
// 导师顾问:跳转到存客宝添加微信
|
||||
// 团队招募:跳转到存客宝添加微信
|
||||
let MATCH_TYPES = [
|
||||
{ id: 'partner', label: '找伙伴', matchLabel: '找伙伴', icon: '⭐', matchFromDB: true, showJoinAfterMatch: false },
|
||||
{ id: 'investor', label: '资源对接', matchLabel: '资源对接', icon: '👥', matchFromDB: true, showJoinAfterMatch: true, requirePurchase: true },
|
||||
{ id: 'mentor', label: '导师顾问', matchLabel: '导师顾问', icon: '❤️', matchFromDB: true, showJoinAfterMatch: true },
|
||||
{ id: 'team', label: '团队招募', matchLabel: '团队招募', icon: '🎮', matchFromDB: true, showJoinAfterMatch: true }
|
||||
]
|
||||
|
||||
let FREE_MATCH_LIMIT = 3 // 每日免费匹配次数
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
|
||||
// 匹配类型
|
||||
matchTypes: MATCH_TYPES,
|
||||
selectedType: 'partner',
|
||||
currentTypeLabel: '找伙伴',
|
||||
|
||||
// 用户状态
|
||||
isLoggedIn: false,
|
||||
hasPurchased: false,
|
||||
hasFullBook: false,
|
||||
|
||||
// 匹配次数
|
||||
todayMatchCount: 0,
|
||||
totalMatchesAllowed: FREE_MATCH_LIMIT,
|
||||
matchesRemaining: FREE_MATCH_LIMIT,
|
||||
needPayToMatch: false,
|
||||
|
||||
// 匹配状态
|
||||
isMatching: false,
|
||||
matchAttempts: 0,
|
||||
currentMatch: null,
|
||||
|
||||
// 加入弹窗
|
||||
showJoinModal: false,
|
||||
joinType: null,
|
||||
joinTypeLabel: '',
|
||||
contactType: 'phone',
|
||||
phoneNumber: '',
|
||||
wechatId: '',
|
||||
userPhone: '',
|
||||
isJoining: false,
|
||||
joinSuccess: false,
|
||||
joinError: '',
|
||||
needBindFirst: false,
|
||||
|
||||
// 资源对接表单
|
||||
canHelp: '',
|
||||
needHelp: '',
|
||||
goodAt: '',
|
||||
|
||||
// 解锁弹窗
|
||||
showUnlockModal: false,
|
||||
|
||||
// 手机/微信号弹窗(stitch_soul)
|
||||
showContactModal: false,
|
||||
contactPhone: '',
|
||||
contactWechat: '',
|
||||
contactSaving: false,
|
||||
|
||||
// 匹配价格(可配置)
|
||||
matchPrice: 1,
|
||||
extraMatches: 0
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
wx.showShareMenu({ withShareTimeline: true })
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight || 44
|
||||
})
|
||||
this.loadMatchConfig()
|
||||
this.loadStoredContact()
|
||||
this.loadTodayMatchCount()
|
||||
this.initUserStatus()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
const tabBar = this.getTabBar()
|
||||
if (tabBar.updateSelected) {
|
||||
tabBar.updateSelected()
|
||||
} else {
|
||||
tabBar.setData({ selected: 2 })
|
||||
}
|
||||
}
|
||||
this.initUserStatus()
|
||||
},
|
||||
|
||||
// 加载匹配配置
|
||||
async loadMatchConfig() {
|
||||
try {
|
||||
const res = await app.request({ url: '/api/miniprogram/match/config', silent: true, method: 'GET',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
if (res.success && res.data) {
|
||||
// 更新全局配置,导师顾问类型强制显示「导师顾问」
|
||||
let types = res.data.matchTypes || MATCH_TYPES
|
||||
types = types.map(t => {
|
||||
if (t.id === 'mentor') {
|
||||
return { ...t, label: '导师顾问', matchLabel: '导师顾问' }
|
||||
}
|
||||
return t
|
||||
})
|
||||
MATCH_TYPES = types
|
||||
FREE_MATCH_LIMIT = res.data.freeMatchLimit || FREE_MATCH_LIMIT
|
||||
const matchPrice = res.data.matchPrice || 1
|
||||
|
||||
this.setData({
|
||||
matchTypes: MATCH_TYPES,
|
||||
totalMatchesAllowed: FREE_MATCH_LIMIT,
|
||||
matchPrice: matchPrice
|
||||
})
|
||||
|
||||
console.log('[Match] 加载匹配配置成功:', {
|
||||
types: MATCH_TYPES.length,
|
||||
freeLimit: FREE_MATCH_LIMIT,
|
||||
price: matchPrice
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Match] 加载匹配配置失败,使用默认配置:', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 加载本地存储的联系方式
|
||||
loadStoredContact() {
|
||||
const phone = wx.getStorageSync('user_phone') || ''
|
||||
const wechat = wx.getStorageSync('user_wechat') || ''
|
||||
this.setData({
|
||||
phoneNumber: phone,
|
||||
wechatId: wechat,
|
||||
userPhone: phone
|
||||
})
|
||||
},
|
||||
|
||||
// 加载今日匹配次数
|
||||
loadTodayMatchCount() {
|
||||
try {
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
const stored = wx.getStorageSync('match_count_data')
|
||||
if (stored) {
|
||||
const data = typeof stored === 'string' ? JSON.parse(stored) : stored
|
||||
if (data.date === today) {
|
||||
this.setData({ todayMatchCount: data.count })
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载匹配次数失败:', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 保存今日匹配次数
|
||||
saveTodayMatchCount(count) {
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
wx.setStorageSync('match_count_data', { date: today, count })
|
||||
},
|
||||
|
||||
// 初始化用户状态
|
||||
initUserStatus() {
|
||||
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
|
||||
|
||||
// 获取额外购买的匹配次数
|
||||
const extraMatches = wx.getStorageSync('extra_match_count') || 0
|
||||
|
||||
// 总匹配次数 = 每日免费(3) + 额外购买次数
|
||||
// 全书用户无限制
|
||||
const totalMatchesAllowed = hasFullBook ? 999999 : FREE_MATCH_LIMIT + extraMatches
|
||||
const matchesRemaining = hasFullBook ? 999999 : Math.max(0, totalMatchesAllowed - this.data.todayMatchCount)
|
||||
const needPayToMatch = !hasFullBook && matchesRemaining <= 0
|
||||
|
||||
this.setData({
|
||||
isLoggedIn,
|
||||
hasFullBook,
|
||||
hasPurchased: true, // 所有用户都可以使用匹配功能
|
||||
totalMatchesAllowed,
|
||||
matchesRemaining,
|
||||
needPayToMatch,
|
||||
extraMatches
|
||||
})
|
||||
},
|
||||
|
||||
// 选择匹配类型
|
||||
selectType(e) {
|
||||
const typeId = e.currentTarget.dataset.type
|
||||
const type = MATCH_TYPES.find(t => t.id === typeId)
|
||||
this.setData({
|
||||
selectedType: typeId,
|
||||
currentTypeLabel: type?.matchLabel || type?.label || '创业伙伴'
|
||||
})
|
||||
},
|
||||
|
||||
// 点击匹配按钮
|
||||
async handleMatchClick() {
|
||||
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
|
||||
|
||||
// 导师顾问:先播匹配动画,动画完成后再跳转(不在此处直接跳)
|
||||
// 找伙伴/资源对接:需先完善联系方式
|
||||
if (this.data.isLoggedIn && currentType?.matchFromDB) {
|
||||
await this.ensureContactInfo(() => this._handleMatchClickInner(currentType))
|
||||
} else {
|
||||
this._handleMatchClickInner(currentType)
|
||||
}
|
||||
},
|
||||
|
||||
async ensureContactInfo(callback) {
|
||||
const userId = app.globalData.userInfo?.id
|
||||
if (!userId) { callback(); return }
|
||||
try {
|
||||
const res = await app.request({ url: `/api/miniprogram/user/profile?userId=${userId}`, silent: true })
|
||||
const phone = (res?.data?.phone || '').trim()
|
||||
const wechat = (res?.data?.wechatId || '').trim()
|
||||
if (phone || wechat) {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
showContactModal: true,
|
||||
contactPhone: phone || '',
|
||||
contactWechat: wechat || '',
|
||||
})
|
||||
this._contactCallback = callback
|
||||
} catch (e) {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
|
||||
closeContactModal() {
|
||||
this.setData({ showContactModal: false })
|
||||
this._contactCallback = null
|
||||
},
|
||||
|
||||
onContactPhoneInput(e) { this.setData({ contactPhone: e.detail.value }) },
|
||||
onContactWechatInput(e) { this.setData({ contactWechat: e.detail.value }) },
|
||||
|
||||
async saveContactInfo() {
|
||||
const phone = (this.data.contactPhone || '').trim()
|
||||
const wechat = (this.data.contactWechat || '').trim()
|
||||
if (!phone && !wechat) {
|
||||
wx.showToast({ title: '请至少填写手机号或微信号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
this.setData({ contactSaving: true })
|
||||
try {
|
||||
await app.request({
|
||||
url: '/api/miniprogram/user/profile',
|
||||
method: 'POST',
|
||||
data: {
|
||||
userId: app.globalData.userInfo?.id,
|
||||
phone: phone || undefined,
|
||||
wechatId: wechat || undefined,
|
||||
},
|
||||
})
|
||||
if (phone) wx.setStorageSync('user_phone', phone)
|
||||
if (wechat) wx.setStorageSync('user_wechat', wechat)
|
||||
this.loadStoredContact()
|
||||
this.closeContactModal()
|
||||
wx.showToast({ title: '已保存', icon: 'success' })
|
||||
const cb = this._contactCallback
|
||||
this._contactCallback = null
|
||||
if (cb) cb()
|
||||
} catch (e) {
|
||||
wx.showToast({ title: e.message || '保存失败', icon: 'none' })
|
||||
}
|
||||
this.setData({ contactSaving: false })
|
||||
},
|
||||
|
||||
_handleMatchClickInner(currentType) {
|
||||
|
||||
// 资源对接类型需要登录+购买章节才能使用
|
||||
if (currentType && currentType.id === 'investor') {
|
||||
// 检查是否登录
|
||||
if (!this.data.isLoggedIn) {
|
||||
wx.showModal({
|
||||
title: '需要登录',
|
||||
content: '请先登录后再使用资源对接功能',
|
||||
confirmText: '去登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.switchTab({ url: '/pages/my/my' })
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否购买过章节
|
||||
const hasPurchased = app.globalData.purchasedSections?.length > 0 || app.globalData.hasFullBook
|
||||
if (!hasPurchased) {
|
||||
wx.showModal({
|
||||
title: '需要购买章节',
|
||||
content: '购买任意章节后即可使用资源对接功能',
|
||||
confirmText: '去购买',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.switchTab({ url: '/pages/catalog/catalog' })
|
||||
}
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是需要填写联系方式的类型(资源对接、导师顾问、团队招募)
|
||||
if (currentType && currentType.showJoinAfterMatch) {
|
||||
// 先检查是否已绑定联系方式
|
||||
const hasPhone = !!this.data.phoneNumber
|
||||
const hasWechat = !!this.data.wechatId
|
||||
|
||||
if (!hasPhone && !hasWechat) {
|
||||
// 没有绑定联系方式,先显示绑定提示
|
||||
this.setData({
|
||||
showJoinModal: true,
|
||||
joinType: currentType.id,
|
||||
joinTypeLabel: currentType.matchLabel || currentType.label,
|
||||
joinSuccess: false,
|
||||
joinError: '',
|
||||
needBindFirst: true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 已绑定联系方式,先显示匹配动画1-3秒,再弹出确认
|
||||
this.startMatchingAnimation(currentType)
|
||||
return
|
||||
}
|
||||
|
||||
// 创业合伙类型 - 真正的匹配功能
|
||||
if (this.data.needPayToMatch) {
|
||||
this.setData({ showUnlockModal: true })
|
||||
return
|
||||
}
|
||||
|
||||
this.startMatch()
|
||||
},
|
||||
|
||||
// 匹配动画后弹出加入确认(导师顾问:动画完成后直接跳转导师页)
|
||||
startMatchingAnimation(currentType) {
|
||||
// 显示匹配中状态
|
||||
this.setData({
|
||||
isMatching: true,
|
||||
matchAttempts: 0,
|
||||
currentMatch: null
|
||||
})
|
||||
|
||||
// 动画计时
|
||||
const timer = setInterval(() => {
|
||||
this.setData({ matchAttempts: this.data.matchAttempts + 1 })
|
||||
}, 500)
|
||||
|
||||
// 1.5-3秒后:导师顾问→跳转;其他类型→弹窗
|
||||
const delay = Math.random() * 1500 + 1500
|
||||
setTimeout(() => {
|
||||
clearInterval(timer)
|
||||
this.setData({ isMatching: false })
|
||||
if (currentType && currentType.id === 'mentor') {
|
||||
wx.navigateTo({ url: '/pages/mentors/mentors' })
|
||||
} else {
|
||||
this.setData({
|
||||
showJoinModal: true,
|
||||
joinType: currentType.id,
|
||||
joinTypeLabel: currentType.matchLabel || currentType.label,
|
||||
joinSuccess: false,
|
||||
joinError: '',
|
||||
needBindFirst: false
|
||||
})
|
||||
}
|
||||
}, delay)
|
||||
},
|
||||
|
||||
// 显示购买提示
|
||||
showPurchaseTip() {
|
||||
wx.showModal({
|
||||
title: '需要购买书籍',
|
||||
content: '购买《Soul创业派对》后即可使用匹配功能,仅需9.9元',
|
||||
confirmText: '去购买',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.goToChapters()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 开始匹配 - 只匹配数据库中的真实用户
|
||||
async startMatch() {
|
||||
this.setData({
|
||||
isMatching: true,
|
||||
matchAttempts: 0,
|
||||
currentMatch: null
|
||||
})
|
||||
|
||||
// 匹配动画计时器
|
||||
const timer = setInterval(() => {
|
||||
this.setData({ matchAttempts: this.data.matchAttempts + 1 })
|
||||
}, 1000)
|
||||
|
||||
// 从数据库获取真实用户匹配
|
||||
let matchedUser = null
|
||||
try {
|
||||
const res = await app.request({ url: '/api/miniprogram/match/users', silent: true,
|
||||
method: 'POST',
|
||||
data: {
|
||||
matchType: this.data.selectedType,
|
||||
userId: app.globalData.userInfo?.id || ''
|
||||
}
|
||||
})
|
||||
|
||||
if (res.success && res.data) {
|
||||
matchedUser = res.data
|
||||
console.log('[Match] 从数据库匹配到用户:', matchedUser.nickname)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Match] 数据库匹配失败:', e)
|
||||
}
|
||||
|
||||
// 延迟显示结果(模拟匹配过程)
|
||||
const delay = Math.random() * 2000 + 2000
|
||||
setTimeout(() => {
|
||||
clearInterval(timer)
|
||||
|
||||
// 如果没有匹配到用户,提示用户
|
||||
if (!matchedUser) {
|
||||
this.setData({ isMatching: false })
|
||||
wx.showModal({
|
||||
title: '暂无匹配',
|
||||
content: '当前暂无合适的匹配用户,请稍后再试',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 增加今日匹配次数
|
||||
const newCount = this.data.todayMatchCount + 1
|
||||
const matchesRemaining = this.data.hasFullBook ? 999999 : Math.max(0, this.data.totalMatchesAllowed - newCount)
|
||||
|
||||
this.setData({
|
||||
isMatching: false,
|
||||
currentMatch: matchedUser,
|
||||
todayMatchCount: newCount,
|
||||
matchesRemaining,
|
||||
needPayToMatch: !this.data.hasFullBook && matchesRemaining <= 0
|
||||
})
|
||||
this.saveTodayMatchCount(newCount)
|
||||
|
||||
// 上报匹配行为到存客宝
|
||||
this.reportMatch(matchedUser)
|
||||
|
||||
}, delay)
|
||||
},
|
||||
|
||||
// 生成模拟匹配数据
|
||||
generateMockMatch() {
|
||||
const nicknames = ['创业先锋', '资源整合者', '私域专家', '导师顾问', '连续创业者']
|
||||
const concepts = [
|
||||
'专注私域流量运营5年,帮助100+品牌实现从0到1的增长。',
|
||||
'连续创业者,擅长商业模式设计和资源整合。',
|
||||
'在Soul分享真实创业故事,希望找到志同道合的合作伙伴。'
|
||||
]
|
||||
const wechats = ['soul_partner_1', 'soul_business_2024', 'soul_startup_fan']
|
||||
|
||||
const index = Math.floor(Math.random() * nicknames.length)
|
||||
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
|
||||
|
||||
return {
|
||||
id: `user_${Date.now()}`,
|
||||
nickname: nicknames[index],
|
||||
avatar: `https://picsum.photos/200/200?random=${Date.now()}`,
|
||||
tags: ['创业者', '私域运营', currentType?.label || '创业合伙'],
|
||||
matchScore: Math.floor(Math.random() * 20) + 80,
|
||||
concept: concepts[index % concepts.length],
|
||||
wechat: wechats[index % wechats.length],
|
||||
commonInterests: [
|
||||
{ icon: '📚', text: '都在读《创业派对》' },
|
||||
{ icon: '💼', text: '对私域运营感兴趣' },
|
||||
{ icon: '🎯', text: '相似的创业方向' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// 上报匹配行为
|
||||
async reportMatch(matchedUser) {
|
||||
try {
|
||||
await app.request({ url: '/api/miniprogram/ckb/match', silent: true,
|
||||
method: 'POST',
|
||||
data: {
|
||||
matchType: this.data.selectedType,
|
||||
phone: this.data.phoneNumber,
|
||||
wechat: this.data.wechatId,
|
||||
userId: app.globalData.userInfo?.id || '',
|
||||
nickname: app.globalData.userInfo?.nickname || '',
|
||||
matchedUser: {
|
||||
id: matchedUser.id,
|
||||
nickname: matchedUser.nickname,
|
||||
matchScore: matchedUser.matchScore
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('上报匹配失败:', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 取消匹配
|
||||
cancelMatch() {
|
||||
this.setData({ isMatching: false, matchAttempts: 0 })
|
||||
},
|
||||
|
||||
// 重置匹配(返回)
|
||||
resetMatch() {
|
||||
this.setData({ currentMatch: null })
|
||||
},
|
||||
|
||||
// 添加微信好友
|
||||
handleAddWechat() {
|
||||
if (!this.data.currentMatch) return
|
||||
|
||||
wx.setClipboardData({
|
||||
data: this.data.currentMatch.wechat,
|
||||
success: () => {
|
||||
wx.showModal({
|
||||
title: '微信号已复制',
|
||||
content: `微信号:${this.data.currentMatch.wechat}\n\n请打开微信添加好友,备注"创业合作"即可`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 切换联系方式类型
|
||||
switchContactType(e) {
|
||||
const type = e.currentTarget.dataset.type
|
||||
this.setData({ contactType: type, joinError: '' })
|
||||
},
|
||||
|
||||
// 手机号输入
|
||||
onPhoneInput(e) {
|
||||
this.setData({
|
||||
phoneNumber: e.detail.value.replace(/\D/g, '').slice(0, 11),
|
||||
joinError: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 资源对接表单输入
|
||||
onCanHelpInput(e) {
|
||||
this.setData({ canHelp: e.detail.value })
|
||||
},
|
||||
onNeedHelpInput(e) {
|
||||
this.setData({ needHelp: e.detail.value })
|
||||
},
|
||||
onGoodAtInput(e) {
|
||||
this.setData({ goodAt: e.detail.value })
|
||||
},
|
||||
|
||||
// 微信号输入
|
||||
onWechatInput(e) {
|
||||
this.setData({
|
||||
wechatId: e.detail.value,
|
||||
joinError: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 提交加入
|
||||
async handleJoinSubmit() {
|
||||
const { contactType, phoneNumber, wechatId, joinType, isJoining, canHelp, needHelp } = this.data
|
||||
|
||||
if (isJoining) return
|
||||
|
||||
// 验证联系方式
|
||||
if (contactType === 'phone') {
|
||||
if (!phoneNumber || phoneNumber.length !== 11) {
|
||||
this.setData({ joinError: '请输入正确的11位手机号' })
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!wechatId || wechatId.length < 6) {
|
||||
this.setData({ joinError: '请输入正确的微信号(至少6位)' })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 资源对接需要填写两项信息
|
||||
if (joinType === 'investor') {
|
||||
if (!canHelp || canHelp.trim().length < 2) {
|
||||
this.setData({ joinError: '请填写"我能帮到你什么"' })
|
||||
return
|
||||
}
|
||||
if (!needHelp || needHelp.trim().length < 2) {
|
||||
this.setData({ joinError: '请填写"我需要什么帮助"' })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({ isJoining: true, joinError: '' })
|
||||
|
||||
try {
|
||||
const res = await app.request('/api/miniprogram/ckb/join', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
type: joinType,
|
||||
phone: contactType === 'phone' ? phoneNumber : '',
|
||||
wechat: contactType === 'wechat' ? wechatId : '',
|
||||
userId: app.globalData.userInfo?.id || '',
|
||||
// 资源对接专属字段
|
||||
canHelp: joinType === 'investor' ? canHelp : '',
|
||||
needHelp: joinType === 'investor' ? needHelp : ''
|
||||
}
|
||||
})
|
||||
|
||||
// 保存联系方式到本地
|
||||
if (phoneNumber) wx.setStorageSync('user_phone', phoneNumber)
|
||||
if (wechatId) wx.setStorageSync('user_wechat', wechatId)
|
||||
|
||||
if (res.success) {
|
||||
this.setData({ joinSuccess: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ showJoinModal: false, joinSuccess: false })
|
||||
}, 2000)
|
||||
} else {
|
||||
// 即使API返回失败,也模拟成功(因为已保存本地)
|
||||
this.setData({ joinSuccess: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ showJoinModal: false, joinSuccess: false })
|
||||
}, 2000)
|
||||
}
|
||||
} catch (e) {
|
||||
// 网络错误时也模拟成功
|
||||
this.setData({ joinSuccess: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ showJoinModal: false, joinSuccess: false })
|
||||
}, 2000)
|
||||
} finally {
|
||||
this.setData({ isJoining: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 关闭加入弹窗
|
||||
closeJoinModal() {
|
||||
if (this.data.isJoining) return
|
||||
this.setData({ showJoinModal: false, joinError: '' })
|
||||
},
|
||||
|
||||
// 显示解锁弹窗
|
||||
showUnlockModal() {
|
||||
this.setData({ showUnlockModal: true })
|
||||
},
|
||||
|
||||
// 关闭解锁弹窗
|
||||
closeUnlockModal() {
|
||||
this.setData({ showUnlockModal: false })
|
||||
},
|
||||
|
||||
// 购买匹配次数
|
||||
async buyMatchCount() {
|
||||
this.setData({ showUnlockModal: false })
|
||||
|
||||
try {
|
||||
// 获取openId
|
||||
let openId = app.globalData.openId || wx.getStorageSync('openId')
|
||||
if (!openId) {
|
||||
openId = await app.getOpenId()
|
||||
}
|
||||
|
||||
if (!openId) {
|
||||
wx.showToast({ title: '请先登录', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 邀请码:与章节支付一致,写入订单便于分销归属与对账
|
||||
const referralCode = wx.getStorageSync('referral_code') || ''
|
||||
// 调用支付接口购买匹配次数
|
||||
const res = await app.request('/api/miniprogram/pay', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
openId,
|
||||
productType: 'match',
|
||||
productId: 'match_1',
|
||||
amount: 1,
|
||||
description: '匹配次数x1',
|
||||
userId: app.globalData.userInfo?.id || '',
|
||||
referralCode: referralCode || undefined
|
||||
}
|
||||
})
|
||||
|
||||
if (res.success && res.data?.payParams) {
|
||||
// 调用微信支付
|
||||
await new Promise((resolve, reject) => {
|
||||
wx.requestPayment({
|
||||
...res.data.payParams,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
|
||||
// 支付成功,增加匹配次数
|
||||
const extraMatches = (wx.getStorageSync('extra_match_count') || 0) + 1
|
||||
wx.setStorageSync('extra_match_count', extraMatches)
|
||||
|
||||
wx.showToast({ title: '购买成功', icon: 'success' })
|
||||
this.initUserStatus()
|
||||
} else {
|
||||
throw new Error(res.error || '创建订单失败')
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.errMsg && e.errMsg.includes('cancel')) {
|
||||
wx.showToast({ title: '已取消', icon: 'none' })
|
||||
} else {
|
||||
// 测试模式
|
||||
wx.showModal({
|
||||
title: '支付服务暂不可用',
|
||||
content: '是否使用测试模式购买?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
const extraMatches = (wx.getStorageSync('extra_match_count') || 0) + 1
|
||||
wx.setStorageSync('extra_match_count', extraMatches)
|
||||
wx.showToast({ title: '测试购买成功', icon: 'success' })
|
||||
this.initUserStatus()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 跳转到目录页购买
|
||||
goToChapters() {
|
||||
this.setData({ showUnlockModal: false })
|
||||
wx.switchTab({ url: '/pages/chapters/chapters' })
|
||||
},
|
||||
|
||||
// 打开设置
|
||||
openSettings() {
|
||||
wx.navigateTo({ url: '/pages/settings/settings' })
|
||||
},
|
||||
|
||||
// 阻止事件冒泡
|
||||
preventBubble() {},
|
||||
|
||||
onShareAppMessage() {
|
||||
const ref = app.getMyReferralCode()
|
||||
return {
|
||||
title: 'Soul创业派对 - 找伙伴',
|
||||
path: ref ? `/pages/match/match?ref=${ref}` : '/pages/match/match'
|
||||
}
|
||||
},
|
||||
|
||||
onShareTimeline() {
|
||||
const ref = app.getMyReferralCode()
|
||||
return { title: 'Soul创业派对 - 找伙伴', query: ref ? `ref=${ref}` : '' }
|
||||
}
|
||||
})
|
||||
6
miniprogram/pages/match/match.json
Normal file
6
miniprogram/pages/match/match.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
328
miniprogram/pages/match/match.wxml
Normal file
328
miniprogram/pages/match/match.wxml
Normal file
@@ -0,0 +1,328 @@
|
||||
<!--pages/match/match.wxml-->
|
||||
<!--Soul创业派对 - 找伙伴页 按H5网页端完全重构-->
|
||||
<view class="page">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-content">
|
||||
<view class="nav-settings" bindtap="openSettings">
|
||||
<text class="settings-icon">⚙️</text>
|
||||
</view>
|
||||
<text class="nav-title">找伙伴</text>
|
||||
<view class="nav-right-placeholder"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<!-- 顶部留白,让内容往下 -->
|
||||
<view style="height: 30rpx;"></view>
|
||||
|
||||
<!-- 匹配提示条 - 简化显示 -->
|
||||
<view class="match-tip-bar" wx:if="{{matchesRemaining <= 0 && !hasFullBook}}">
|
||||
<text class="tip-icon">⚡</text>
|
||||
<text class="tip-text">今日免费次数已用完</text>
|
||||
<view class="tip-btn" bindtap="showUnlockModal">购买次数</view>
|
||||
</view>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<view class="main-content">
|
||||
<!-- 空闲状态 - 未匹配 -->
|
||||
<block wx:if="{{!isMatching && !currentMatch}}">
|
||||
<!-- 中央匹配圆环 -->
|
||||
<view class="match-circle-wrapper" bindtap="handleMatchClick">
|
||||
<!-- 外层光环 -->
|
||||
<view class="outer-glow glow-active"></view>
|
||||
<!-- 中间光环 -->
|
||||
<view class="middle-ring ring-active"></view>
|
||||
<!-- 内层球体 -->
|
||||
<view class="inner-sphere sphere-active">
|
||||
<view class="sphere-gradient"></view>
|
||||
<view class="sphere-content">
|
||||
<block wx:if="{{needPayToMatch}}">
|
||||
<text class="sphere-icon">⚡</text>
|
||||
<text class="sphere-title gold-text">购买次数</text>
|
||||
<text class="sphere-desc">¥1 = 1次匹配</text>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<text class="sphere-icon">👥</text>
|
||||
<text class="sphere-title">开始匹配</text>
|
||||
<text class="sphere-desc">匹配{{currentTypeLabel}}</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 当前模式显示 -->
|
||||
<view class="current-mode">
|
||||
当前模式: <text class="text-brand">{{currentTypeLabel}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<view class="divider"></view>
|
||||
|
||||
<!-- 选择匹配类型 -->
|
||||
<view class="type-section">
|
||||
<text class="type-section-title">选择匹配类型</text>
|
||||
<view class="type-grid">
|
||||
<view
|
||||
class="type-item {{selectedType === item.id ? 'type-active' : ''}}"
|
||||
wx:for="{{matchTypes}}"
|
||||
wx:key="id"
|
||||
bindtap="selectType"
|
||||
data-type="{{item.id}}"
|
||||
>
|
||||
<text class="type-icon">{{item.icon}}</text>
|
||||
<text class="type-label {{selectedType === item.id ? 'text-brand' : ''}}">{{item.label}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 匹配中状态 - 美化特效 -->
|
||||
<block wx:if="{{isMatching}}">
|
||||
<view class="matching-state">
|
||||
<view class="matching-animation-v2">
|
||||
<!-- 外层旋转光环 -->
|
||||
<view class="matching-outer-ring"></view>
|
||||
<!-- 中层脉冲环 -->
|
||||
<view class="matching-pulse-ring"></view>
|
||||
<!-- 内层球体 -->
|
||||
<view class="matching-core">
|
||||
<view class="matching-core-inner">
|
||||
<text class="matching-icon-v2">🔍</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 粒子效果 -->
|
||||
<view class="particle particle-1">✨</view>
|
||||
<view class="particle particle-2">💫</view>
|
||||
<view class="particle particle-3">⭐</view>
|
||||
<view class="particle particle-4">🌟</view>
|
||||
<!-- 扩散波纹 -->
|
||||
<view class="ripple-v2 ripple-v2-1"></view>
|
||||
<view class="ripple-v2 ripple-v2-2"></view>
|
||||
<view class="ripple-v2 ripple-v2-3"></view>
|
||||
</view>
|
||||
<text class="matching-title-v2">正在匹配{{currentTypeLabel}}...</text>
|
||||
<text class="matching-subtitle-v2">正在从 {{matchAttempts * 127 + 89}} 位创业者中为你寻找</text>
|
||||
<view class="matching-tips">
|
||||
<text class="tip-item" wx:if="{{matchAttempts >= 1}}">✓ 分析兴趣标签</text>
|
||||
<text class="tip-item" wx:if="{{matchAttempts >= 2}}">✓ 匹配创业方向</text>
|
||||
<text class="tip-item" wx:if="{{matchAttempts >= 3}}">✓ 筛选优质伙伴</text>
|
||||
</view>
|
||||
<view class="cancel-btn-v2" bindtap="cancelMatch">取消</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 匹配成功状态 -->
|
||||
<block wx:if="{{currentMatch && !isMatching}}">
|
||||
<view class="matched-state">
|
||||
<!-- 成功动画 -->
|
||||
<view class="success-icon-wrapper">
|
||||
<text class="success-icon">✨</text>
|
||||
</view>
|
||||
|
||||
<!-- 用户卡片 -->
|
||||
<view class="match-card">
|
||||
<view class="card-header">
|
||||
<image class="match-avatar" src="{{currentMatch.avatar}}" mode="aspectFill"></image>
|
||||
<view class="match-info">
|
||||
<text class="match-name">{{currentMatch.nickname}}</text>
|
||||
<view class="match-tags">
|
||||
<text class="match-tag" wx:for="{{currentMatch.tags}}" wx:key="*this">{{item}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="match-score-box">
|
||||
<text class="score-value">{{currentMatch.matchScore}}%</text>
|
||||
<text class="score-label">匹配度</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 共同兴趣 -->
|
||||
<view class="card-section">
|
||||
<text class="section-title">共同兴趣</text>
|
||||
<view class="interest-list">
|
||||
<view class="interest-item" wx:for="{{currentMatch.commonInterests}}" wx:key="text">
|
||||
<text class="interest-icon">{{item.icon}}</text>
|
||||
<text class="interest-text">{{item.text}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心理念 -->
|
||||
<view class="card-section">
|
||||
<text class="section-title">核心理念</text>
|
||||
<text class="concept-text">{{currentMatch.concept}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-buttons">
|
||||
<view class="btn-primary" bindtap="handleAddWechat">一键加好友</view>
|
||||
<view class="btn-secondary" bindtap="resetMatch">返回</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 加入弹窗 - 简洁版 -->
|
||||
<view class="modal-overlay" wx:if="{{showJoinModal}}" bindtap="closeJoinModal">
|
||||
<view class="modal-content join-modal-new" catchtap="preventBubble">
|
||||
<!-- 成功状态 -->
|
||||
<block wx:if="{{joinSuccess}}">
|
||||
<view class="join-success-new">
|
||||
<view class="success-icon-big">✅</view>
|
||||
<text class="success-title-new">提交成功</text>
|
||||
<text class="success-desc-new">工作人员将在24小时内与您联系</text>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 表单状态 -->
|
||||
<block wx:else>
|
||||
<!-- 头部 -->
|
||||
<view class="join-header">
|
||||
<view class="join-icon-wrap">
|
||||
<text class="join-icon">{{joinType === 'investor' ? '👥' : joinType === 'mentor' ? '❤️' : '🎮'}}</text>
|
||||
</view>
|
||||
<text class="join-title">{{joinTypeLabel}}</text>
|
||||
<text class="join-subtitle" wx:if="{{needBindFirst}}">请先绑定联系方式</text>
|
||||
<text class="join-subtitle" wx:else>填写联系方式,专人对接</text>
|
||||
<view class="close-btn-new" bindtap="closeJoinModal">✕</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系方式切换 -->
|
||||
<view class="contact-switch">
|
||||
<view
|
||||
class="switch-item {{contactType === 'phone' ? 'switch-active' : ''}}"
|
||||
bindtap="switchContactType"
|
||||
data-type="phone"
|
||||
>
|
||||
<text class="switch-icon">📱</text>
|
||||
<text>手机号</text>
|
||||
</view>
|
||||
<view
|
||||
class="switch-item {{contactType === 'wechat' ? 'switch-active' : ''}}"
|
||||
bindtap="switchContactType"
|
||||
data-type="wechat"
|
||||
>
|
||||
<text class="switch-icon">💬</text>
|
||||
<text>微信号</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 资源对接专用输入(只有两项:我能帮到你什么、我需要什么帮助) -->
|
||||
<block wx:if="{{joinType === 'investor'}}">
|
||||
<view class="resource-form">
|
||||
<view class="form-item">
|
||||
<text class="form-label">我能帮到你什么 <text class="required">*</text></text>
|
||||
<view class="form-input-wrap">
|
||||
<input class="form-input-inner" type="text" placeholder="例如:私域运营、品牌策划、流量资源..." value="{{canHelp}}" bindinput="onCanHelpInput" maxlength="100"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">我需要什么帮助 <text class="required">*</text></text>
|
||||
<view class="form-input-wrap">
|
||||
<input class="form-input-inner" placeholder="例如:技术支持、资金、人脉..." value="{{needHelp}}" bindinput="onNeedHelpInput" maxlength="100"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 联系方式输入区域(Skill §6:view 包裹、padding 写 view、input width 100%) -->
|
||||
<view class="input-area">
|
||||
<view class="input-wrapper">
|
||||
<text class="input-prefix">{{contactType === 'phone' ? '+86' : '@'}}</text>
|
||||
<view class="input-field-wrap">
|
||||
<input
|
||||
wx:if="{{contactType === 'phone'}}"
|
||||
type="number"
|
||||
class="input-field-inner"
|
||||
placeholder="请输入11位手机号"
|
||||
placeholder-class="input-placeholder-new"
|
||||
value="{{phoneNumber}}"
|
||||
bindinput="onPhoneInput"
|
||||
maxlength="11"
|
||||
disabled="{{isJoining}}"
|
||||
focus="{{contactType === 'phone'}}"
|
||||
/>
|
||||
<input
|
||||
wx:else
|
||||
type="text"
|
||||
class="input-field-inner"
|
||||
placeholder="请输入微信号"
|
||||
placeholder-class="input-placeholder-new"
|
||||
value="{{wechatId}}"
|
||||
bindinput="onWechatInput"
|
||||
disabled="{{isJoining}}"
|
||||
focus="{{contactType === 'wechat'}}"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<text class="error-msg" wx:if="{{joinError}}">{{joinError}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view
|
||||
class="submit-btn-new {{isJoining || !(contactType === 'phone' ? phoneNumber : wechatId) ? 'btn-disabled-new' : ''}}"
|
||||
bindtap="handleJoinSubmit"
|
||||
>
|
||||
{{isJoining ? '提交中...' : '确认提交'}}
|
||||
</view>
|
||||
|
||||
<text class="form-notice-new">提交后我们会尽快与您联系</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机/微信号弹窗(stitch_soul comprehensive_profile_editor_v1_2) -->
|
||||
<view class="modal-overlay contact-modal-overlay" wx:if="{{showContactModal}}" bindtap="closeContactModal">
|
||||
<view class="contact-modal" catchtap="preventBubble">
|
||||
<text class="contact-modal-title">请完善联系方式</text>
|
||||
<view class="contact-modal-hint">需完善手机号或微信号才能使用找伙伴功能</view>
|
||||
<view class="form-input-wrap">
|
||||
<text class="form-label">手机号</text>
|
||||
<view class="form-input-inner">
|
||||
<text class="form-icon">📱</text>
|
||||
<input class="form-input" type="tel" placeholder="请输入您的手机号" value="{{contactPhone}}" bindinput="onContactPhoneInput"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-input-wrap">
|
||||
<text class="form-label">微信号</text>
|
||||
<view class="form-input-inner">
|
||||
<text class="form-icon">💬</text>
|
||||
<input class="form-input" type="text" placeholder="请输入您的微信号" value="{{contactWechat}}" bindinput="onContactWechatInput"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="contact-modal-btn" bindtap="saveContactInfo" disabled="{{contactSaving}}">
|
||||
{{contactSaving ? '保存中...' : '保存'}}
|
||||
</view>
|
||||
<text class="contact-modal-cancel" bindtap="closeContactModal">取消</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 解锁弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showUnlockModal}}" bindtap="closeUnlockModal">
|
||||
<view class="modal-content unlock-modal" catchtap="preventBubble">
|
||||
<view class="unlock-icon">⚡</view>
|
||||
<text class="unlock-title">购买匹配次数</text>
|
||||
<text class="unlock-desc">今日3次免费匹配已用完,可付费购买额外次数</text>
|
||||
|
||||
<view class="unlock-info">
|
||||
<view class="info-row">
|
||||
<text class="info-label">单价</text>
|
||||
<text class="info-value text-brand">¥{{matchPrice || 1}} / 次</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">已购买</text>
|
||||
<text class="info-value">{{extraMatches || 0}} 次</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="unlock-buttons">
|
||||
<view class="btn-gold" bindtap="buyMatchCount">立即购买 ¥{{matchPrice || 1}}</view>
|
||||
<view class="btn-ghost" bindtap="closeUnlockModal">明天再来</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部留白 -->
|
||||
<view class="bottom-space"></view>
|
||||
</view>
|
||||
1245
miniprogram/pages/match/match.wxss
Normal file
1245
miniprogram/pages/match/match.wxss
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user