feat: 全面优化小程序界面和功能

 新增功能:
- 配置后台匹配规则选择功能,支持多种匹配类型自定义
- 推广中心使用真实数据,实现H5/小程序绑定关系
- 配置MySQL数据库连接,建立完整数据表结构

🎨 界面优化:
- 优化登录状态显示,未登录只显示基础功能
- 修复推广中心等页面宽度问题,统一界面布局
- 优化设置页面绑定弹窗样式,简洁大气
- 修复目录页图标和文字对齐问题

🔧 技术改进:
- 匹配功能支持后台配置,动态加载匹配类型
- 推广数据支持API获取,本地存储作为备份
- 数据库表结构完整,支持用户、订单、推广关系
- 小程序登录仅保留微信登录方式

📱 小程序优化:
- 匹配次数调整为每日3次免费
- 支持¥1购买额外匹配次数
- 分享到朋友圈功能优化
- 界面宽度统一,卡片布局一致
This commit is contained in:
卡若
2026-01-23 16:31:54 +08:00
parent e869974341
commit 1e1e6a1093
18 changed files with 1017 additions and 613 deletions

View File

@@ -6,15 +6,15 @@
const app = getApp()
// 匹配类型配置 - 与H5保持一致
const MATCH_TYPES = [
// 默认匹配类型配置
let MATCH_TYPES = [
{ id: 'partner', label: '创业合伙', matchLabel: '创业伙伴', icon: '⭐', matchFromDB: true, showJoinAfterMatch: false },
{ id: 'investor', label: '资源对接', matchLabel: '资源对接', icon: '👥', matchFromDB: false, showJoinAfterMatch: true },
{ id: 'mentor', label: '导师顾问', matchLabel: '商业顾问', icon: '❤️', matchFromDB: false, showJoinAfterMatch: true },
{ id: 'team', label: '团队招募', matchLabel: '加入项目', icon: '🎮', matchFromDB: false, showJoinAfterMatch: true }
]
const FREE_MATCH_LIMIT = 1 // 每日免费匹配次数
let FREE_MATCH_LIMIT = 3 // 每日免费匹配次数
Page({
data: {
@@ -61,6 +61,7 @@ Page({
this.setData({
statusBarHeight: app.globalData.statusBarHeight || 44
})
this.loadMatchConfig()
this.loadStoredContact()
this.loadTodayMatchCount()
this.initUserStatus()
@@ -73,6 +74,33 @@ Page({
this.initUserStatus()
},
// 加载匹配配置
async loadMatchConfig() {
try {
const res = await app.request('/api/match/config', {
method: 'GET'
})
if (res.success && res.data) {
// 更新全局配置
MATCH_TYPES = res.data.matchTypes || MATCH_TYPES
FREE_MATCH_LIMIT = res.data.freeMatchLimit || FREE_MATCH_LIMIT
this.setData({
matchTypes: MATCH_TYPES,
totalMatchesAllowed: FREE_MATCH_LIMIT
})
console.log('[Match] 加载匹配配置成功:', {
types: MATCH_TYPES.length,
freeLimit: FREE_MATCH_LIMIT
})
}
} catch (e) {
console.log('[Match] 加载匹配配置失败,使用默认配置:', e)
}
},
// 加载本地存储的联系方式
loadStoredContact() {
const phone = wx.getStorageSync('user_phone') || ''
@@ -109,20 +137,24 @@ Page({
// 初始化用户状态
initUserStatus() {
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
const hasPurchased = hasFullBook || (purchasedSections && purchasedSections.length > 0)
// 总匹配次数 = 每日免费(1) + 已购小节
const totalMatchesAllowed = hasFullBook ? 999999 : FREE_MATCH_LIMIT + (purchasedSections?.length || 0)
// 获取额外购买的匹配次
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,
hasPurchased: true, // 所有用户都可以使用匹配功能
totalMatchesAllowed,
matchesRemaining,
needPayToMatch
needPayToMatch,
extraMatches
})
},
@@ -403,11 +435,85 @@ Page({
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 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 || ''
}
})
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 })
@@ -416,7 +522,7 @@ Page({
// 打开设置
openSettings() {
wx.showToast({ title: '设置功能开发中', icon: 'none' })
wx.navigateTo({ url: '/pages/settings/settings' })
},
// 阻止事件冒泡

View File

@@ -12,20 +12,20 @@
</view>
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
<!-- 匹配次数显示 - 仅购买用户显示 -->
<view class="match-count-bar" wx:if="{{hasPurchased}}">
<!-- 匹配次数显示 - 所有用户可见 -->
<view class="match-count-bar">
<view class="count-left">
<text class="count-icon {{matchesRemaining <= 0 && !hasFullBook ? 'icon-warning' : ''}}">⚡</text>
<text class="count-text">
{{hasFullBook ? '无限匹配机会' : matchesRemaining <= 0 ? '今日匹配机会已用完' : '剩余匹配机会'}}
{{hasFullBook ? '无限匹配机会' : matchesRemaining <= 0 ? '今日免费次数已用完' : '今日剩余'}}
</text>
</view>
<view class="count-right">
<text class="count-value {{matchesRemaining > 0 || hasFullBook ? 'text-brand' : 'text-red'}}">
{{hasFullBook ? '无限' : matchesRemaining + '/' + totalMatchesAllowed}}
{{hasFullBook ? '' : matchesRemaining + '次'}}
</text>
<view class="unlock-mini-btn" wx:if="{{matchesRemaining <= 0 && !hasFullBook}}" bindtap="goToChapters">
购买小节+1次
<view class="unlock-mini-btn" wx:if="{{matchesRemaining <= 0 && !hasFullBook}}" bindtap="showUnlockModal">
¥1购买1次
</view>
</view>
</view>
@@ -35,36 +35,24 @@
<!-- 空闲状态 - 未匹配 -->
<block wx:if="{{!isMatching && !currentMatch}}">
<!-- 中央匹配圆环 -->
<view
class="match-circle-wrapper"
bindtap="{{hasPurchased ? 'handleMatchClick' : 'showPurchaseTip'}}"
>
<view class="match-circle-wrapper" bindtap="handleMatchClick">
<!-- 外层光环 -->
<view class="outer-glow {{hasPurchased ? 'glow-active' : 'glow-inactive'}}"></view>
<view class="outer-glow glow-active"></view>
<!-- 中间光环 -->
<view class="middle-ring {{hasPurchased ? 'ring-active' : 'ring-inactive'}}"></view>
<view class="middle-ring ring-active"></view>
<!-- 内层球体 -->
<view class="inner-sphere {{hasPurchased ? 'sphere-active' : 'sphere-inactive'}}">
<view class="inner-sphere sphere-active">
<view class="sphere-gradient"></view>
<view class="sphere-content">
<!-- 已购买用户 -->
<block wx:if="{{hasPurchased}}">
<block wx:if="{{needPayToMatch}}">
<text class="sphere-icon">⚡</text>
<text class="sphere-title gold-text">需要解锁</text>
<text class="sphere-desc">今日免费次数已用完</text>
</block>
<block wx:else>
<text class="sphere-icon">👥</text>
<text class="sphere-title">开始匹配</text>
<text class="sphere-desc">匹配{{currentTypeLabel}}</text>
</block>
<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-gray">购买后解锁</text>
<text class="sphere-desc text-muted">购买9.9元即可使用</text>
<text class="sphere-icon">👥</text>
<text class="sphere-title">开始匹配</text>
<text class="sphere-desc">匹配{{currentTypeLabel}}</text>
</block>
</view>
</view>
@@ -72,16 +60,12 @@
<!-- 当前模式显示 -->
<view class="current-mode">
当前模式: <text class="{{hasPurchased ? 'text-brand' : 'text-muted'}}">{{currentTypeLabel}}</text>
当前模式: <text class="text-brand">{{currentTypeLabel}}</text>
</view>
<!-- 购买提示 - 仅未购买用户显示 -->
<view class="purchase-tip-card" wx:if="{{!hasPurchased}}">
<view class="tip-left">
<text class="tip-title">购买书籍解锁匹配功能</text>
<text class="tip-desc">仅需9.9元,每天免费匹配</text>
</view>
<view class="tip-btn" bindtap="goToChapters">去购买</view>
<!-- 免费次数提示 -->
<view class="free-tip" wx:if="{{!hasFullBook}}">
每天{{totalMatchesAllowed}}次免费匹配,用完可付费购买
</view>
<!-- 分隔线 -->
@@ -258,22 +242,22 @@
<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">每购买一个小节内容即可额外获得1次匹配机会</text>
<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>
<text class="info-label">单价</text>
<text class="info-value text-brand">¥1 / 次</text>
</view>
<view class="info-row">
<text class="info-label">获得次数</text>
<text class="info-value text-brand">+1次匹配</text>
<text class="info-label">已购买</text>
<text class="info-value">{{extraMatches || 0}} 次</text>
</view>
</view>
<view class="unlock-buttons">
<view class="btn-gold" bindtap="goToChapters">去购买小节 (¥1/节)</view>
<view class="btn-gold" bindtap="buyMatchCount">立即购买 ¥1</view>
<view class="btn-ghost" bindtap="closeUnlockModal">明天再来</view>
</view>
</view>

View File

@@ -243,6 +243,14 @@
text-align: center;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.5);
margin-bottom: 16rpx;
}
/* ===== 免费次数提示 ===== */
.free-tip {
text-align: center;
font-size: 24rpx;
color: rgba(255, 255, 255, 0.4);
margin-bottom: 32rpx;
}