更新小程序配置,重构页面结构,删除不再使用的地址管理和章节页面,优化项目结构以提升可维护性;调整全局样式,增强组件的可复用性和一致性。

This commit is contained in:
2026-02-03 11:35:38 +08:00
parent d74410cfb5
commit a7d781a25b
79 changed files with 10610 additions and 3518 deletions

View File

@@ -1,292 +0,0 @@
const app = getApp()
const MATCH_TYPES = [
{ id: 'partner', label: '创业合伙', matchLabel: '创业伙伴', icon: '⭐' },
{ id: 'investor', label: '资源对接', matchLabel: '资源对接', icon: '👥' },
{ id: 'mentor', label: '导师顾问', matchLabel: '商业顾问', icon: '❤️' },
{ id: 'team', label: '团队招募', matchLabel: '加入项目', icon: '🎮' }
]
const FREE_MATCH_LIMIT = 1
function getStoredContact() {
try {
return {
phone: wx.getStorageSync('user_phone') || '',
wechat: wx.getStorageSync('user_wechat') || ''
}
} catch (e) { return { phone: '', wechat: '' } }
}
function getTodayMatchCount() {
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) return data.count || 0
}
} catch (e) {}
return 0
}
function saveTodayMatchCount(count) {
try {
const today = new Date().toISOString().split('T')[0]
wx.setStorageSync('match_count_data', JSON.stringify({ date: today, count }))
} catch (e) {}
}
function saveContact(phone, wechat) {
try {
if (phone) wx.setStorageSync('user_phone', phone)
if (wechat) wx.setStorageSync('user_wechat', wechat)
} catch (e) {}
}
Page({
data: {
statusBarHeight: 44,
navBarHeight: 88,
matchEnabled: false,
matchTypes: MATCH_TYPES,
selectedType: 'partner',
currentMatchLabel: '创业伙伴',
hasPurchased: false,
todayMatchCount: 0,
totalMatchesAllowed: 1,
matchesRemaining: 0,
needPayToMatch: false,
isMatching: false,
currentMatch: null,
matchAttempts: 0,
showUnlockModal: false,
showJoinModal: false,
joinType: null,
phoneNumber: '',
wechatId: '',
contactType: 'phone',
isJoining: false,
joinSuccess: false,
joinError: '',
isUnlocking: false
},
onLoad() {
this.setNavBarHeight()
const contact = getStoredContact()
this.setData({ phoneNumber: contact.phone, wechatId: contact.wechat })
app.loadFeatureConfig().then(() => this.syncState())
},
onShow() {
if (typeof this.getTabBar === 'function' && this.getTabBar()) this.getTabBar().setData({ selected: 2 })
this.setNavBarHeight()
app.loadFeatureConfig().then(() => this.syncState())
},
setNavBarHeight() {
const statusBarHeight = app.globalData.statusBarHeight || 44
const navBarHeight = app.globalData.navBarHeight || (statusBarHeight + 44)
this.setData({ statusBarHeight, navBarHeight })
},
syncState() {
const matchEnabled = app.globalData.matchEnabled === true
const user = app.globalData.userInfo
const hasFullBook = !!app.globalData.hasFullBook
const purchasedSections = app.globalData.purchasedSections || []
const hasPurchased = hasFullBook || purchasedSections.length > 0
const todayMatchCount = getTodayMatchCount()
const totalMatchesAllowed = hasFullBook ? 999999 : FREE_MATCH_LIMIT + purchasedSections.length
const matchesRemaining = hasFullBook ? 999999 : Math.max(0, totalMatchesAllowed - todayMatchCount)
const needPayToMatch = !hasFullBook && matchesRemaining <= 0
if (user && user.phone) this.setData({ phoneNumber: user.phone })
this.setData({
matchEnabled,
hasPurchased,
todayMatchCount,
totalMatchesAllowed,
matchesRemaining,
needPayToMatch
})
},
selectType(e) {
const id = e.currentTarget.dataset.id
const t = MATCH_TYPES.find(x => x.id === id)
this.setData({ selectedType: id, currentMatchLabel: t ? t.matchLabel : '创业伙伴' })
},
startMatch() {
if (!this.data.hasPurchased) {
wx.showToast({ title: '购买书籍后可使用', icon: 'none' })
return
}
if (this.data.needPayToMatch) {
this.setData({ showUnlockModal: true })
return
}
this.setData({ isMatching: true, currentMatch: null, matchAttempts: 0 })
let attempts = 0
const timer = setInterval(() => {
attempts++
this.setData({ matchAttempts: attempts })
}, 1000)
const delay = 3000 + Math.random() * 3000
setTimeout(() => {
clearInterval(timer)
const matched = this.getMockMatch()
const newCount = this.data.todayMatchCount + 1
saveTodayMatchCount(newCount)
this.reportMatchToCKB(matched)
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
const showJoinAfter = currentType && (currentType.id === 'investor' || currentType.id === 'mentor' || currentType.id === 'team')
this.setData({
isMatching: false,
currentMatch: matched,
todayMatchCount: newCount,
matchesRemaining: this.data.hasFullBook ? 999999 : Math.max(0, this.data.totalMatchesAllowed - newCount),
needPayToMatch: !this.data.hasFullBook && (this.data.totalMatchesAllowed - newCount) <= 0
})
if (showJoinAfter) {
this.setData({ showJoinModal: true, joinType: this.data.selectedType, joinSuccess: false, joinError: '' })
}
}, delay)
},
getMockMatch() {
const nicknames = ['创业先锋', '资源整合者', '私域专家', '商业导师', '连续创业者']
const concepts = [
'专注私域流量运营5年帮助100+品牌实现从0到1的增长。',
'连续创业者,擅长商业模式设计和资源整合。',
'在Soul分享真实创业故事希望找到志同道合的合作伙伴。'
]
const wechats = ['soul_partner_1', 'soul_business_2024', 'soul_startup_fan']
const i = Math.floor(Math.random() * nicknames.length)
const typeLabel = MATCH_TYPES.find(t => t.id === this.data.selectedType)
return {
id: 'user_' + Date.now(),
nickname: nicknames[i],
avatar: '',
tags: ['创业者', '私域运营', typeLabel ? typeLabel.label : ''],
matchScore: 80 + Math.floor(Math.random() * 20),
concept: concepts[i % concepts.length],
wechat: wechats[i % wechats.length],
commonInterests: [
{ icon: '📚', text: '都在读《创业实验》' },
{ icon: '💼', text: '对私域运营感兴趣' },
{ icon: '🎯', text: '相似的创业方向' }
]
}
},
reportMatchToCKB(matched) {
app.request('/api/ckb/match', {
method: 'POST',
data: {
matchType: this.data.selectedType,
phone: this.data.phoneNumber || (app.globalData.userInfo && app.globalData.userInfo.phone) || '',
wechat: this.data.wechatId || (app.globalData.userInfo && app.globalData.userInfo.wechat) || '',
userId: (app.globalData.userInfo && app.globalData.userInfo.id) || '',
nickname: (app.globalData.userInfo && app.globalData.userInfo.nickname) || '',
matchedUser: { id: matched.id, nickname: matched.nickname, matchScore: matched.matchScore }
}
}).catch(() => {})
},
cancelMatch() {
this.setData({ isMatching: false })
},
nextMatch() {
if (this.data.needPayToMatch) {
this.setData({ showUnlockModal: true })
return
}
this.setData({ currentMatch: null })
this.startMatch()
},
addWechat() {
const m = this.data.currentMatch
if (!m || !m.wechat) return
wx.setClipboardData({
data: m.wechat,
success: () => {
wx.showModal({
title: '已复制微信号',
content: '请打开微信添加好友,备注"创业合作"即可。',
showCancel: false
})
}
})
},
closeUnlockModal() {
if (!this.data.isUnlocking) this.setData({ showUnlockModal: false })
},
goBuySection() {
this.setData({ showUnlockModal: false })
wx.switchTab({ url: '/pages/chapters/chapters' })
},
closeJoinModal() {
if (!this.data.isJoining) this.setData({ showJoinModal: false })
},
setContactType(e) {
const t = e.currentTarget.dataset.type
this.setData({ contactType: t })
},
onPhoneInput(e) {
this.setData({ phoneNumber: (e.detail && e.detail.value) || '' })
},
onWechatInput(e) {
this.setData({ wechatId: (e.detail && e.detail.value) || '' })
},
submitJoin() {
const { contactType, phoneNumber, wechatId } = this.data
if (contactType === 'phone' && (!phoneNumber || phoneNumber.length !== 11)) {
this.setData({ joinError: '请输入正确的11位手机号' })
return
}
if (contactType === 'wechat' && (!wechatId || wechatId.length < 6)) {
this.setData({ joinError: '请输入正确的微信号至少6位' })
return
}
this.setData({ isJoining: true, joinError: '' })
app.request('/api/ckb/join', {
method: 'POST',
data: {
type: this.data.joinType,
phone: contactType === 'phone' ? phoneNumber : '',
wechat: contactType === 'wechat' ? wechatId : '',
userId: app.globalData.userInfo && app.globalData.userInfo.id
}
}).then((res) => {
if (res && res.success) {
saveContact(phoneNumber, wechatId)
this.setData({ joinSuccess: true })
setTimeout(() => this.setData({ showJoinModal: false, joinSuccess: false }), 2000)
} else {
this.setData({ joinError: (res && res.message) || '加入失败,请稍后重试' })
}
}).catch(() => {
this.setData({ joinError: '网络错误,请检查网络后重试' })
}).finally(() => {
this.setData({ isJoining: false })
})
},
goToChapters() {
wx.switchTab({ url: '/pages/chapters/chapters' })
},
goToIndex() {
wx.switchTab({ url: '/pages/index/index' })
}
})

View File

@@ -1,4 +0,0 @@
{
"navigationBarTitleText": "找伙伴",
"usingComponents": {}
}

View File

@@ -1,155 +0,0 @@
<view class="page">
<view class="nav-placeholder" style="height: {{navBarHeight || (statusBarHeight + 44)}}px;"></view>
<block wx:if="{{!matchEnabled}}">
<view class="closed-wrap">
<view class="closed-icon">🔒</view>
<text class="closed-title">功能暂未开放</text>
<text class="closed-desc">找伙伴功能即将上线,请先逛逛首页与目录。</text>
<view class="btn-primary" bindtap="goToIndex">返回首页</view>
</view>
</block>
<block wx:else>
<view class="header safe-header-right">
<text class="header-title">找伙伴</text>
<view class="header-btn"></view>
</view>
<view class="match-count-card" wx:if="{{hasPurchased}}">
<view class="match-count-left">
<text class="match-count-label {{matchesRemaining <= 0 && !needPayToMatch ? '' : ''}}">{{needPayToMatch ? '今日匹配机会已用完' : (totalMatchesAllowed > 999 ? '无限匹配机会' : '剩余匹配机会')}}</text>
</view>
<view class="match-count-right">
<text class="match-count-num {{matchesRemaining > 0 ? 'active' : 'red'}}">{{totalMatchesAllowed > 999 ? '无限' : matchesRemaining + '/' + totalMatchesAllowed}}</text>
<view class="btn-buy-section" wx:if="{{needPayToMatch}}" bindtap="goToChapters">购买小节+1次</view>
</view>
</view>
<block wx:if="{{!isMatching && !currentMatch}}">
<view class="idle-wrap">
<view class="circle-wrap {{hasPurchased ? 'active' : ''}} {{needPayToMatch ? 'need-pay' : ''}}" bindtap="startMatch">
<view class="circle-inner">
<block wx:if="{{!hasPurchased}}">
<text class="circle-icon">🔒</text>
<text class="circle-title">购买后解锁</text>
<text class="circle-desc">购买9.9元即可使用</text>
</block>
<block wx:elif="{{needPayToMatch}}">
<text class="circle-icon gold">⚡</text>
<text class="circle-title">需要解锁</text>
<text class="circle-desc">今日免费次数已用完</text>
</block>
<block wx:else>
<text class="circle-icon">👥</text>
<text class="circle-title">开始匹配</text>
<text class="circle-desc">匹配{{currentMatchLabel}}</text>
</block>
</view>
</view>
<text class="idle-mode">当前模式: {{selectedType === 'partner' ? '创业合伙' : (selectedType === 'investor' ? '资源对接' : (selectedType === 'mentor' ? '导师顾问' : '团队招募'))}}</text>
<view class="buy-tip" wx:if="{{!hasPurchased}}" bindtap="goToChapters">
<view class="buy-tip-left">
<text class="buy-tip-title">购买书籍解锁匹配功能</text>
<text class="buy-tip-desc">仅需9.9元每天3次免费匹配</text>
</view>
<view class="btn-go-buy">去购买</view>
</view>
<view class="divider"></view>
<text class="type-label">选择匹配类型</text>
<view class="type-grid">
<view class="type-item {{selectedType === item.id ? 'active' : ''}}" wx:for="{{matchTypes}}" wx:key="id" data-id="{{item.id}}" bindtap="selectType">
<text class="type-icon">{{item.icon}}</text>
<text class="type-text">{{item.label}}</text>
</view>
</view>
</view>
</block>
<block wx:if="{{isMatching}}">
<view class="matching-wrap">
<view class="matching-spinner"></view>
<text class="matching-title">正在匹配{{currentMatchLabel}}...</text>
<text class="matching-count">已匹配 {{matchAttempts}} 次</text>
<view class="btn-cancel" bindtap="cancelMatch">取消匹配</view>
</view>
</block>
<block wx:if="{{currentMatch && !isMatching}}">
<view class="matched-wrap">
<text class="matched-emoji">✨</text>
<view class="matched-card">
<view class="matched-head">
<image class="matched-avatar" src="{{currentMatch.avatar || '/images/placeholder-user.jpg'}}" mode="aspectFill" />
<view class="matched-info">
<text class="matched-name">{{currentMatch.nickname}}</text>
<view class="matched-tags">
<text class="matched-tag" wx:for="{{currentMatch.tags}}" wx:key="*this" wx:for-item="tag">{{tag}}</text>
</view>
</view>
<view class="matched-score-wrap">
<text class="matched-score">{{currentMatch.matchScore}}%</text>
<text class="matched-score-label">匹配度</text>
</view>
</view>
<view class="matched-interests">
<text class="matched-label">共同兴趣</text>
<view class="interest-row" wx:for="{{currentMatch.commonInterests}}" wx:key="text">
<text class="interest-icon">{{item.icon}}</text>
<text class="interest-text">{{item.text}}</text>
</view>
</view>
<view class="matched-concept">
<text class="matched-label">核心理念</text>
<text class="matched-concept-text">{{currentMatch.concept}}</text>
</view>
</view>
<view class="btn-add-wechat" bindtap="addWechat">一键加好友</view>
<view class="btn-next" bindtap="nextMatch">重新匹配</view>
</view>
</block>
</block>
<view class="mask" wx:if="{{showUnlockModal}}" catchtap="closeUnlockModal">
<view class="modal unlock-modal" catchtap="">
<view class="modal-icon-wrap"><text class="modal-icon gold">⚡</text></view>
<text class="modal-title">匹配机会已用完</text>
<text class="modal-desc">每购买一个小节内容即可额外获得1次匹配机会</text>
<view class="modal-row"><text class="modal-row-label">解锁方式</text><text class="modal-row-value">购买任意小节</text></view>
<view class="modal-row"><text class="modal-row-label">获得次数</text><text class="modal-row-value brand">+1次匹配</text></view>
<view class="btn-primary" bindtap="goBuySection">去购买小节 (¥1/节)</view>
<view class="btn-ghost" bindtap="closeUnlockModal">明天再来</view>
</view>
</view>
<view class="mask" wx:if="{{showJoinModal}}" catchtap="closeJoinModal">
<view class="modal join-modal" catchtap="">
<view class="modal-head">
<text class="modal-head-title">加入{{joinType === 'partner' ? '创业伙伴' : (joinType === 'investor' ? '资源对接' : (joinType === 'mentor' ? '商业顾问' : '加入项目'))}}</text>
<view class="modal-close" bindtap="closeJoinModal">×</view>
</view>
<view class="modal-body" wx:if="{{!joinSuccess}}">
<text class="modal-hint">请填写您的联系方式以便我们联系您</text>
<view class="contact-tabs">
<view class="contact-tab {{contactType === 'phone' ? 'active' : ''}}" data-type="phone" bindtap="setContactType">手机号</view>
<view class="contact-tab {{contactType === 'wechat' ? 'active' : ''}}" data-type="wechat" bindtap="setContactType">微信号</view>
</view>
<view class="input-wrap" wx:if="{{contactType === 'phone'}}">
<input class="input" type="number" maxlength="11" placeholder="请输入11位手机号" value="{{phoneNumber}}" bindinput="onPhoneInput" />
</view>
<view class="input-wrap" wx:else>
<input class="input" placeholder="请输入微信号" value="{{wechatId}}" bindinput="onWechatInput" />
</view>
<text class="error-text" wx:if="{{joinError}}">{{joinError}}</text>
<view class="btn-primary {{(contactType === 'phone' ? !phoneNumber : !wechatId) || isJoining ? 'disabled' : ''}}" bindtap="submitJoin">{{isJoining ? '提交中...' : '确认加入'}}</view>
</view>
<view class="modal-body success-wrap" wx:else>
<text class="success-emoji">✓</text>
<text class="success-title">加入成功!</text>
<text class="success-desc">我们会尽快与您联系</text>
</view>
</view>
</view>
<view class="bottom-space"></view>
</view>

View File

@@ -1,103 +0,0 @@
.page { min-height: 100vh; background: #000; padding-bottom: 200rpx; }
.nav-placeholder { width: 100%; }
.bottom-space { height: 40rpx; }
.closed-wrap { display: flex; flex-direction: column; align-items: center; padding: 120rpx 48rpx; }
.closed-icon { font-size: 120rpx; margin-bottom: 32rpx; opacity: 0.6; }
.closed-title { font-size: 40rpx; font-weight: 600; color: #fff; margin-bottom: 16rpx; }
.closed-desc { font-size: 28rpx; color: rgba(255,255,255,0.5); text-align: center; margin-bottom: 64rpx; }
.btn-primary { padding: 24rpx 64rpx; border-radius: 48rpx; background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%); color: #000; font-size: 32rpx; font-weight: 600; }
.btn-primary.disabled { opacity: 0.5; }
.header { display: flex; align-items: center; justify-content: space-between; padding: 24rpx 32rpx 16rpx; }
.header-title { font-size: 48rpx; font-weight: 700; color: #fff; }
.header-btn { width: 80rpx; height: 80rpx; border-radius: 50%; background: #1c1c1e; }
.match-count-card { margin: 0 32rpx 24rpx; padding: 24rpx 32rpx; border-radius: 24rpx; background: #1c1c1e; border: 2rpx solid rgba(255,255,255,0.05); display: flex; align-items: center; justify-content: space-between; }
.match-count-card .match-count-num.red { color: #f87171; }
.match-count-card .match-count-num.active { color: #00E5FF; }
.match-count-label { font-size: 28rpx; color: rgba(255,255,255,0.7); }
.match-count-num { font-size: 36rpx; font-weight: 700; }
.btn-buy-section { padding: 12rpx 24rpx; border-radius: 32rpx; background: rgba(255,215,0,0.2); font-size: 24rpx; color: #FFD700; margin-left: 16rpx; }
.idle-wrap { padding: 0 32rpx; display: flex; flex-direction: column; align-items: center; }
.circle-wrap { width: 560rpx; height: 560rpx; border-radius: 50%; margin-bottom: 48rpx; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 50%); border: 4rpx solid rgba(255,255,255,0.1); }
.circle-wrap.active { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%); border-color: rgba(0,229,255,0.3); }
.circle-wrap.need-pay { border-color: rgba(255,215,0,0.3); }
.circle-inner { text-align: center; }
.circle-icon { font-size: 96rpx; display: block; margin-bottom: 24rpx; }
.circle-icon.gold { color: #FFD700; }
.circle-title { font-size: 40rpx; font-weight: 700; color: #fff; display: block; margin-bottom: 8rpx; }
.circle-desc { font-size: 28rpx; color: rgba(255,255,255,0.5); }
.idle-mode { font-size: 28rpx; color: rgba(255,255,255,0.5); margin-bottom: 32rpx; }
.buy-tip { width: 100%; padding: 32rpx; border-radius: 24rpx; background: linear-gradient(90deg, rgba(0,229,255,0.1) 0%, transparent 100%); border: 2rpx solid rgba(0,229,255,0.2); display: flex; align-items: center; justify-content: space-between; margin-bottom: 32rpx; }
.buy-tip-left { }
.buy-tip-title { font-size: 30rpx; color: #fff; font-weight: 500; display: block; }
.buy-tip-desc { font-size: 24rpx; color: rgba(255,255,255,0.5); margin-top: 8rpx; display: block; }
.btn-go-buy { padding: 16rpx 32rpx; border-radius: 16rpx; background: #00E5FF; color: #000; font-size: 28rpx; font-weight: 500; }
.divider { width: 100%; height: 2rpx; background: rgba(255,255,255,0.1); margin-bottom: 24rpx; }
.type-label { font-size: 28rpx; color: rgba(255,255,255,0.4); margin-bottom: 24rpx; align-self: flex-start; }
.type-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24rpx; width: 100%; }
.type-item { padding: 32rpx 16rpx; border-radius: 24rpx; background: #1c1c1e; border: 2rpx solid transparent; display: flex; flex-direction: column; align-items: center; gap: 16rpx; }
.type-item.active { background: rgba(0,229,255,0.1); border-color: rgba(0,229,255,0.5); }
.type-icon { font-size: 48rpx; }
.type-text { font-size: 24rpx; color: rgba(255,255,255,0.6); }
.type-item.active .type-text { color: #00E5FF; }
.matching-wrap { padding: 80rpx 32rpx; text-align: center; }
.matching-spinner { width: 400rpx; height: 400rpx; margin: 0 auto 48rpx; border-radius: 50%; border: 8rpx solid transparent; border-top-color: #00E5FF; border-right-color: #7B61FF; border-bottom-color: #E91E63; animation: spin 1s linear infinite; }
.matching-title { font-size: 40rpx; font-weight: 600; color: #fff; display: block; margin-bottom: 16rpx; }
.matching-count { font-size: 28rpx; color: rgba(255,255,255,0.5); display: block; margin-bottom: 48rpx; }
.btn-cancel { display: inline-block; padding: 24rpx 64rpx; border-radius: 48rpx; background: #1c1c1e; color: #fff; border: 2rpx solid rgba(255,255,255,0.1); font-size: 28rpx; }
@keyframes spin { to { transform: rotate(360deg); } }
.matched-wrap { padding: 0 32rpx; }
.matched-emoji { font-size: 120rpx; display: block; text-align: center; margin-bottom: 32rpx; }
.matched-card { padding: 40rpx; border-radius: 32rpx; background: #1c1c1e; border: 2rpx solid rgba(255,255,255,0.05); margin-bottom: 24rpx; }
.matched-head { display: flex; align-items: center; gap: 32rpx; margin-bottom: 32rpx; padding-bottom: 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.1); }
.matched-avatar { width: 128rpx; height: 128rpx; border-radius: 50%; border: 4rpx solid #00E5FF; flex-shrink: 0; }
.matched-info { flex: 1; min-width: 0; }
.matched-name { font-size: 36rpx; font-weight: 600; color: #fff; display: block; margin-bottom: 16rpx; }
.matched-tags { display: flex; flex-wrap: wrap; gap: 8rpx; }
.matched-tag { font-size: 22rpx; padding: 8rpx 16rpx; border-radius: 8rpx; background: rgba(0,229,255,0.2); color: #00E5FF; }
.matched-score-wrap { text-align: center; }
.matched-score { font-size: 48rpx; font-weight: 700; color: #00E5FF; display: block; }
.matched-score-label { font-size: 22rpx; color: rgba(255,255,255,0.4); }
.matched-interests { margin-bottom: 24rpx; padding-bottom: 24rpx; border-bottom: 2rpx solid rgba(255,255,255,0.1); }
.matched-concept { }
.matched-label { font-size: 28rpx; color: rgba(255,255,255,0.5); display: block; margin-bottom: 16rpx; }
.interest-row { display: flex; align-items: center; gap: 16rpx; margin-bottom: 8rpx; font-size: 28rpx; color: rgba(255,255,255,0.8); }
.interest-icon { }
.interest-text { }
.matched-concept-text { font-size: 28rpx; color: rgba(255,255,255,0.7); line-height: 1.6; }
.btn-add-wechat { width: 100%; padding: 32rpx; border-radius: 24rpx; background: #00E5FF; color: #000; font-size: 32rpx; font-weight: 500; text-align: center; margin-bottom: 24rpx; }
.btn-next { width: 100%; padding: 32rpx; border-radius: 24rpx; background: #1c1c1e; color: #fff; border: 2rpx solid rgba(255,255,255,0.1); font-size: 32rpx; text-align: center; }
.mask { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.6); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 48rpx; box-sizing: border-box; }
.modal { width: 100%; max-width: 600rpx; background: #1c1c1e; border-radius: 32rpx; padding: 48rpx; }
.modal-icon-wrap { width: 128rpx; height: 128rpx; margin: 0 auto 32rpx; border-radius: 50%; background: rgba(255,215,0,0.2); display: flex; align-items: center; justify-content: center; }
.modal-icon { font-size: 64rpx; }
.modal-icon.gold { color: #FFD700; }
.modal-title { font-size: 40rpx; font-weight: 700; color: #fff; display: block; text-align: center; margin-bottom: 16rpx; }
.modal-desc { font-size: 28rpx; color: rgba(255,255,255,0.5); text-align: center; display: block; margin-bottom: 32rpx; }
.modal-row { display: flex; justify-content: space-between; padding: 16rpx 0; font-size: 28rpx; }
.modal-row-label { color: rgba(255,255,255,0.5); }
.modal-row-value { color: #fff; }
.modal-row-value.brand { color: #00E5FF; }
.btn-ghost { width: 100%; padding: 24rpx; border-radius: 24rpx; background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.6); font-size: 28rpx; text-align: center; margin-top: 24rpx; }
.join-modal .modal-head { display: flex; align-items: center; justify-content: space-between; padding-bottom: 24rpx; border-bottom: 2rpx solid rgba(255,255,255,0.1); margin-bottom: 24rpx; }
.modal-head-title { font-size: 36rpx; font-weight: 600; color: #fff; }
.modal-close { width: 64rpx; height: 64rpx; border-radius: 50%; background: rgba(255,255,255,0.1); display: flex; align-items: center; justify-content: center; font-size: 40rpx; color: rgba(255,255,255,0.6); }
.modal-hint { font-size: 28rpx; color: rgba(255,255,255,0.5); display: block; margin-bottom: 24rpx; }
.contact-tabs { display: flex; gap: 16rpx; margin-bottom: 24rpx; }
.contact-tab { flex: 1; padding: 20rpx; border-radius: 16rpx; background: rgba(255,255,255,0.05); border: 2rpx solid rgba(255,255,255,0.1); text-align: center; font-size: 28rpx; color: rgba(255,255,255,0.5); }
.contact-tab.active { background: rgba(0,229,255,0.2); border-color: rgba(0,229,255,0.3); color: #00E5FF; }
.input-wrap { margin-bottom: 24rpx; }
.input { width: 100%; padding: 24rpx 32rpx; border-radius: 24rpx; background: rgba(0,0,0,0.3); border: 2rpx solid rgba(255,255,255,0.1); color: #fff; font-size: 28rpx; box-sizing: border-box; }
.error-text { font-size: 24rpx; color: #f87171; display: block; margin-bottom: 16rpx; }
.join-modal .btn-primary { width: 100%; text-align: center; margin-top: 16rpx; }
.success-wrap { text-align: center; padding: 48rpx 0; }
.success-emoji { font-size: 128rpx; color: #00E5FF; display: block; margin-bottom: 24rpx; }
.success-title { font-size: 36rpx; font-weight: 600; color: #fff; display: block; margin-bottom: 8rpx; }
.success-desc { font-size: 28rpx; color: rgba(255,255,255,0.5); }