重构匹配页面,通过新增登录和手机号绑定模态窗口来提升用户体验。在添加好友前,增加了通过微信和手机号绑定登录的功能。更新了API配置,并调整了用户联系信息的本地存储处理方式。改进了模态窗口的用户界面元素,并确保用户交互的数据流正确。

This commit is contained in:
乘风
2026-02-11 15:50:53 +08:00
parent 1e9ab0da71
commit ecee1bb2bb
10 changed files with 532 additions and 98 deletions

View File

@@ -7,9 +7,9 @@ App({
globalData: {
// API基础地址 - 连接真实后端
// baseUrl: 'https://soulapi.quwanzhi.com',
baseUrl: 'https://souldev.quwanzhi.com',
// baseUrl: 'https://souldev.quwanzhi.com',
// baseUrl: 'http://localhost:3006',
// baseUrl: 'http://localhost:8080',
baseUrl: 'http://localhost:8080',
// 小程序配置 - 真实AppID
appId: 'wxb8bbb2b10dec74aa',

View File

@@ -66,6 +66,17 @@ Page({
// 解锁弹窗
showUnlockModal: false,
// 手机号绑定弹窗(一键加好友前校验)
showBindPhoneModal: false,
pendingAddWechatAfterBind: false,
bindPhoneInput: '',
showMatchPhoneManualInput: false,
// 登录弹窗(未登录时点击匹配弹出)
showLoginModal: false,
isLoggingIn: false,
agreeProtocol: false,
// 匹配价格(可配置)
matchPrice: 1,
extraMatches: 0
@@ -90,6 +101,7 @@ Page({
tabBar.setData({ selected: 2 })
}
}
this.loadStoredContact()
this.initUserStatus()
},
@@ -123,10 +135,11 @@ Page({
}
},
// 加载本地存储的联系方式
// 加载本地存储的联系方式(含用户资料的手机号、微信号)
loadStoredContact() {
const phone = wx.getStorageSync('user_phone') || ''
const wechat = wx.getStorageSync('user_wechat') || ''
const ui = app.globalData.userInfo || {}
const phone = wx.getStorageSync('user_phone') || ui.phone || ''
const wechat = wx.getStorageSync('user_wechat') || ui.wechat || ui.wechatId || ''
this.setData({
phoneNumber: phone,
wechatId: wechat,
@@ -192,25 +205,16 @@ Page({
// 点击匹配按钮
handleMatchClick() {
// 检测是否登录,未登录则弹出登录弹窗
if (!this.data.isLoggedIn) {
this.setData({ showLoginModal: true, agreeProtocol: false })
return
}
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
// 资源对接类型需要登录+购买章节才能使用
// 资源对接类型需要购买章节才能使用
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) {
@@ -235,7 +239,8 @@ Page({
const hasWechat = !!this.data.wechatId
if (!hasPhone && !hasWechat) {
// 没有绑定联系方式,先显示绑定提示
// 没有绑定联系方式,先显示绑定提示(仍尝试加载已有资料填充)
this.loadStoredContact()
this.setData({
showJoinModal: true,
joinType: currentType.id,
@@ -279,6 +284,8 @@ Page({
const delay = Math.random() * 2000 + 1000
setTimeout(() => {
clearInterval(timer)
// 打开弹窗前调取用户资料填充手机号、微信号
this.loadStoredContact()
this.setData({
isMatching: false,
showJoinModal: true,
@@ -435,26 +442,78 @@ Page({
this.setData({ currentMatch: null })
},
// 添加微信好友
// 添加微信好友(先校验手机号绑定)
handleAddWechat() {
if (!this.data.currentMatch) return
// 未登录需先登录
if (!app.globalData.isLoggedIn) {
wx.showModal({
title: '需要登录',
content: '请先登录后再添加好友',
confirmText: '去登录',
success: (res) => {
if (res.confirm) wx.switchTab({ url: '/pages/my/my' })
}
})
return
}
// 判断是否已绑定手机号(本地缓存或用户资料)
const hasPhone = !!(
wx.getStorageSync('user_phone') ||
app.globalData.userInfo?.phone
)
if (!hasPhone) {
this.setData({
showBindPhoneModal: true,
pendingAddWechatAfterBind: true
})
return
}
this.doCopyWechat()
},
// 执行复制联系方式(优先微信号,无则复制手机号)
doCopyWechat() {
if (!this.data.currentMatch) return
const wechat = (this.data.currentMatch.wechat || this.data.currentMatch.wechatId || '').trim()
const phone = (this.data.currentMatch.phone || '').trim()
const toCopy = wechat || phone
if (!toCopy) {
wx.showModal({
title: '暂无可复制',
content: '该用户未提供微信号或手机号,请通过其他方式联系',
showCancel: false,
confirmText: '知道了'
})
return
}
const label = wechat ? '微信号' : '手机号'
wx.setClipboardData({
data: this.data.currentMatch.wechat,
data: toCopy,
success: () => {
wx.showModal({
title: '微信号已复制',
content: `微信号:${this.data.currentMatch.wechat}\n\n请打开微信添加好友,备注"创业合作"即可`,
title: wechat ? '微信号已复制' : '手机号已复制',
content: wechat
? `${label}${toCopy}\n\n请打开微信添加好友,备注"创业合作"即可`
: `${label}${toCopy}\n\n可通过微信搜索该手机号添加好友`,
showCancel: false,
confirmText: '知道了'
})
},
fail: () => {
wx.showToast({ title: '复制失败,请重试', icon: 'none' })
}
})
},
// 切换联系方式类型
// 切换联系方式类型(同步刷新用户资料填充)
switchContactType(e) {
const type = e.currentTarget.dataset.type
this.loadStoredContact()
this.setData({ contactType: type, joinError: '' })
},
@@ -565,6 +624,149 @@ Page({
this.setData({ showJoinModal: false, joinError: '' })
},
// 关闭手机绑定弹窗
closeBindPhoneModal() {
this.setData({
showBindPhoneModal: false,
pendingAddWechatAfterBind: false,
bindPhoneInput: '',
showMatchPhoneManualInput: false
})
},
// 关闭登录弹窗
closeLoginModal() {
if (this.data.isLoggingIn) return
this.setData({ showLoginModal: false })
},
// 切换协议勾选
toggleAgree() {
this.setData({ agreeProtocol: !this.data.agreeProtocol })
},
// 打开用户协议
openUserProtocol() {
wx.navigateTo({ url: '/pages/agreement/agreement' })
},
// 打开隐私政策
openPrivacy() {
wx.navigateTo({ url: '/pages/privacy/privacy' })
},
// 微信登录(匹配页)
async handleMatchWechatLogin() {
if (!this.data.agreeProtocol) {
wx.showToast({ title: '请先阅读并同意用户协议和隐私政策', icon: 'none' })
return
}
this.setData({ isLoggingIn: true })
try {
const result = await app.login()
if (result) {
this.initUserStatus()
this.setData({ showLoginModal: false, agreeProtocol: false })
wx.showToast({ title: '登录成功', icon: 'success' })
} else {
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
}
} catch (e) {
console.error('[Match] 微信登录错误:', e)
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
} finally {
this.setData({ isLoggingIn: false })
}
},
// 一键获取手机号(匹配页加好友前绑定)
async onMatchGetPhoneNumber(e) {
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
wx.showToast({ title: '授权失败', icon: 'none' })
return
}
const code = e.detail.code
if (!code) {
this.setData({ showMatchPhoneManualInput: true })
return
}
try {
wx.showLoading({ title: '获取中...', mask: true })
const userId = app.globalData.userInfo?.id
const res = await app.request('/api/miniprogram/phone', {
method: 'POST',
data: { code, userId }
})
wx.hideLoading()
if (res.success && res.phoneNumber) {
await this.saveMatchPhoneAndContinue(res.phoneNumber)
} else {
this.setData({ showMatchPhoneManualInput: true })
}
} catch (err) {
wx.hideLoading()
this.setData({ showMatchPhoneManualInput: true })
}
},
// 切换为手动输入
onMatchShowManualInput() {
this.setData({ showMatchPhoneManualInput: true })
},
// 手动输入手机号
onMatchPhoneInput(e) {
this.setData({
bindPhoneInput: e.detail.value.replace(/\D/g, '').slice(0, 11)
})
},
// 确认手动绑定手机号
async confirmMatchPhoneBind() {
const { bindPhoneInput } = this.data
if (!bindPhoneInput || bindPhoneInput.length !== 11) {
wx.showToast({ title: '请输入正确的11位手机号', icon: 'none' })
return
}
if (!/^1[3-9]\d{9}$/.test(bindPhoneInput)) {
wx.showToast({ title: '请输入正确的手机号', icon: 'none' })
return
}
await this.saveMatchPhoneAndContinue(bindPhoneInput)
},
// 保存手机号到本地+服务器,并继续加好友
async saveMatchPhoneAndContinue(phone) {
wx.setStorageSync('user_phone', phone)
if (app.globalData.userInfo) {
app.globalData.userInfo.phone = phone
wx.setStorageSync('userInfo', app.globalData.userInfo)
}
this.setData({
phoneNumber: phone,
userPhone: phone,
bindPhoneInput: ''
})
this.loadStoredContact()
try {
const userId = app.globalData.userInfo?.id
if (userId) {
await app.request('/api/miniprogram/user/profile', {
method: 'POST',
data: { userId, phone }
})
}
} catch (e) {
console.log('[Match] 同步手机号到服务器失败:', e)
}
const pending = this.data.pendingAddWechatAfterBind
this.closeBindPhoneModal()
if (pending) {
wx.showToast({ title: '绑定成功', icon: 'success' })
setTimeout(() => this.doCopyWechat(), 500)
}
},
// 显示解锁弹窗
showUnlockModal() {
this.setData({ showUnlockModal: true })

View File

@@ -265,6 +265,75 @@
</view>
</view>
<!-- 登录弹窗(未登录点击匹配时弹出) -->
<view class="modal-overlay" wx:if="{{showLoginModal}}" bindtap="closeLoginModal">
<view class="modal-content login-modal-content" catchtap="preventBubble">
<view class="modal-close" bindtap="closeLoginModal">✕</view>
<view class="login-icon">🔐</view>
<text class="login-title">登录 Soul创业实验</text>
<text class="login-desc">登录后可使用找伙伴功能</text>
<button
class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}"
bindtap="handleMatchWechatLogin"
disabled="{{isLoggingIn || !agreeProtocol}}"
>
<text class="btn-wechat-icon">微</text>
<text>{{isLoggingIn ? '登录中...' : '微信快捷登录'}}</text>
</button>
<view class="login-modal-cancel" bindtap="closeLoginModal">取消</view>
<view class="login-agree-row" catchtap="toggleAgree">
<view class="agree-checkbox {{agreeProtocol ? 'agree-checked' : ''}}">{{agreeProtocol ? '✓' : ''}}</view>
<text class="agree-text">我已阅读并同意</text>
<text class="agree-link" catchtap="openUserProtocol">《用户协议》</text>
<text class="agree-text">和</text>
<text class="agree-link" catchtap="openPrivacy">《隐私政策》</text>
</view>
</view>
</view>
<!-- 手机号绑定弹窗(一键加好友前) -->
<view class="modal-overlay" wx:if="{{showBindPhoneModal}}" bindtap="closeBindPhoneModal">
<view class="modal-content join-modal-new" catchtap="preventBubble">
<view class="join-header">
<view class="join-icon-wrap">
<text class="join-icon">📱</text>
</view>
<text class="join-title">需要先绑定手机号</text>
<text class="join-subtitle">为保障联系方式真实有效,加好友前请先绑定手机号</text>
<view class="close-btn-new" bindtap="closeBindPhoneModal">✕</view>
</view>
<block wx:if="{{!showMatchPhoneManualInput}}">
<view class="bind-phone-actions">
<button class="get-phone-btn-modal" open-type="getPhoneNumber" bindgetphonenumber="onMatchGetPhoneNumber">
授权获取手机号
</button>
<view class="manual-bind-link" bindtap="onMatchShowManualInput">手动输入手机号</view>
</view>
</block>
<block wx:else>
<view class="input-area" style="padding: 0 40rpx 24rpx;">
<view class="input-wrapper">
<text class="input-prefix">+86</text>
<input
type="number"
class="input-field"
placeholder="请输入11位手机号"
placeholder-class="input-placeholder-new"
value="{{bindPhoneInput}}"
bindinput="onMatchPhoneInput"
maxlength="11"
/>
</view>
</view>
<view class="submit-btn-new" style="margin: 0 40rpx 48rpx;" bindtap="confirmMatchPhoneBind">确认绑定</view>
</block>
</view>
</view>
<!-- 解锁弹窗 -->
<view class="modal-overlay" wx:if="{{showUnlockModal}}" bindtap="closeUnlockModal">
<view class="modal-content unlock-modal" catchtap="preventBubble">

View File

@@ -584,6 +584,133 @@
overflow: hidden;
}
/* ===== 登录弹窗 ===== */
.login-modal-content {
padding: 48rpx;
position: relative;
}
.login-modal-content .modal-close {
position: absolute;
top: 24rpx;
right: 24rpx;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.6);
}
.login-icon {
font-size: 96rpx;
text-align: center;
display: block;
margin-bottom: 24rpx;
}
.login-title {
font-size: 36rpx;
font-weight: 700;
color: #ffffff;
text-align: center;
display: block;
margin-bottom: 16rpx;
}
.login-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.6);
text-align: center;
display: block;
margin-bottom: 48rpx;
}
.btn-wechat {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
padding: 28rpx;
background: #07C160;
color: #ffffff;
font-size: 28rpx;
font-weight: 500;
border-radius: 24rpx;
margin-bottom: 24rpx;
border: none;
}
.btn-wechat::after {
border: none;
}
.btn-wechat-icon {
width: 40rpx;
height: 40rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
}
.login-modal-cancel {
margin-top: 24rpx;
padding: 24rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
text-align: center;
}
.login-agree-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
margin-top: 32rpx;
font-size: 22rpx;
color: rgba(255, 255, 255, 0.5);
}
.agree-checkbox {
width: 32rpx;
height: 32rpx;
border: 2rpx solid rgba(255, 255, 255, 0.5);
border-radius: 6rpx;
margin-right: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
color: #fff;
flex-shrink: 0;
}
.agree-checked {
background: #00CED1;
border-color: #00CED1;
}
.agree-text {
color: rgba(255, 255, 255, 0.6);
}
.agree-link {
color: #00CED1;
text-decoration: underline;
padding: 0 4rpx;
}
.btn-wechat-disabled {
opacity: 0.6;
}
/* ===== 加入弹窗 ===== */
.join-modal {
padding: 40rpx;
@@ -705,7 +832,7 @@
.join-header {
position: relative;
padding: 48rpx 40rpx 32rpx;
padding: 48rpx 48rpx 32rpx;
background: linear-gradient(135deg, rgba(0, 206, 209, 0.15) 0%, rgba(123, 97, 255, 0.1) 100%);
text-align: center;
}
@@ -754,10 +881,39 @@
color: rgba(255, 255, 255, 0.6);
}
/* 手机号绑定弹窗 */
.bind-phone-actions {
padding: 32rpx 40rpx 48rpx;
display: flex;
flex-direction: column;
align-items: center;
gap: 24rpx;
}
.get-phone-btn-modal {
width: 100%;
padding: 28rpx 48rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
color: #fff;
font-size: 32rpx;
font-weight: 600;
border-radius: 20rpx;
border: none;
}
.get-phone-btn-modal::after {
border: none;
}
.manual-bind-link {
font-size: 28rpx;
color: rgba(0, 206, 209, 0.9);
}
.contact-switch {
display: flex;
gap: 16rpx;
padding: 24rpx 40rpx;
padding: 24rpx 48rpx;
}
.switch-item {
@@ -785,7 +941,7 @@
}
.input-area {
padding: 0 40rpx 24rpx;
padding: 0 48rpx 24rpx;
}
.input-wrapper {
@@ -824,7 +980,7 @@
}
.submit-btn-new {
margin: 8rpx 40rpx 24rpx;
margin: 8rpx 48rpx 24rpx;
padding: 28rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
color: #ffffff;
@@ -843,7 +999,7 @@
text-align: center;
font-size: 22rpx;
color: rgba(255, 255, 255, 0.3);
padding-bottom: 32rpx;
padding: 0 48rpx 32rpx;
}
/* ===== 新版加入成功 ===== */
@@ -1181,7 +1337,7 @@
display: flex;
flex-direction: column;
gap: 20rpx;
margin-bottom: 24rpx;
margin: 0 48rpx 24rpx;
}
.resource-form .form-item {
display: flex;

View File

@@ -90,46 +90,8 @@
</view>
</view>
<!-- 收益卡片 - 艺术化设计 - 仅登录用户显示 -->
<view class="earnings-card" wx:if="{{isLoggedIn}}">
<!-- 背景装饰圆 -->
<view class="bg-decoration bg-decoration-gold"></view>
<view class="bg-decoration bg-decoration-brand"></view>
<view class="earnings-content">
<!-- 标题行:右侧为刷新图标 -->
<view class="earnings-header">
<view class="earnings-title-wrap">
<text class="earnings-icon">💰</text>
<text class="earnings-title">我的收益</text>
</view>
<view class="earnings-refresh-wrap" bindtap="refreshEarnings">
<text class="earnings-refresh-icon {{earningsRefreshing ? 'earnings-refresh-spin' : ''}}">↻</text>
</view>
</view>
<!-- 收益数据:加载中显示 - 占位 -->
<view class="earnings-data">
<view class="earnings-main">
<text class="earnings-label">累计收益</text>
<text class="earnings-amount-large gold-gradient">{{earningsLoading ? '-' : '¥' + earnings}}</text>
</view>
<view class="earnings-secondary">
<text class="earnings-label">可提现</text>
<text class="earnings-amount-medium">{{earningsLoading ? '-' : '¥' + pendingEarnings}}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="earnings-action" bindtap="goToReferral">
<text class="action-icon">🎁</text>
<text class="action-text">推广中心 / 提现</text>
</view>
</view>
</view>
<!-- 待确认收款(用户确认模式)- 仅登录用户显示 -->
<view class="pending-confirm-card" wx:if="{{isLoggedIn}}">
<!-- 待确认收款(用户确认模式)- 有数据时显示 -->
<view class="pending-confirm-card" wx:if="{{isLoggedIn && pendingConfirmList.length > 0}}">
<view class="pending-confirm-header">
<text class="pending-confirm-title">待确认收款</text>
<text class="pending-confirm-desc" wx:if="{{pendingConfirmList.length > 0}}">审核已通过,点击下方按钮完成收款</text>

View File

@@ -3,7 +3,7 @@
"projectname": "miniprogram",
"setting": {
"compileHotReLoad": true,
"urlCheck": true,
"urlCheck": false,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,
@@ -23,12 +23,19 @@
"condition": {
"miniprogram": {
"list": [
{
"name": "找伙伴",
"pathName": "pages/match/match",
"query": "",
"scene": null,
"launchMode": "default"
},
{
"name": "pages/read/read",
"pathName": "pages/read/read",
"query": "id=1.1",
"scene": null,
"launchMode": "default"
"launchMode": "default",
"scene": null
},
{
"name": "pages/match/match",

View File

@@ -5,6 +5,7 @@ import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"sort"
@@ -20,6 +21,7 @@ const ckbAPIURL = "https://ckbapi.quwanzhi.com/v1/api/scenarios"
var ckbSourceMap = map[string]string{"team": "团队招募", "investor": "资源对接", "mentor": "导师顾问", "partner": "创业合伙"}
var ckbTagsMap = map[string]string{"team": "切片团队,团队招募", "investor": "资源对接,资源群", "mentor": "导师顾问,咨询服务", "partner": "创业合伙,创业伙伴"}
// ckbSign 与 next-project app/api/ckb/join 一致:排除 sign/apiKey/portrait空值跳过按键升序拼接值MD5(拼接串) 再 MD5(结果+apiKey)
func ckbSign(params map[string]interface{}, apiKey string) string {
keys := make([]string, 0, len(params))
for k := range params {
@@ -35,13 +37,16 @@ func ckbSign(params map[string]interface{}, apiKey string) string {
sort.Strings(keys)
var concat string
for _, k := range keys {
switch v := params[k].(type) {
v := params[k]
switch val := v.(type) {
case string:
concat += v
concat += val
case float64:
concat += strconv.FormatFloat(v, 'f', -1, 64)
concat += strconv.FormatFloat(val, 'f', -1, 64)
case int:
concat += strconv.Itoa(v)
concat += strconv.Itoa(val)
case int64:
concat += strconv.FormatInt(val, 10)
default:
concat += ""
}
@@ -55,12 +60,14 @@ func ckbSign(params map[string]interface{}, apiKey string) string {
// CKBJoin POST /api/ckb/join
func CKBJoin(c *gin.Context) {
var body struct {
Type string `json:"type" binding:"required"`
Phone string `json:"phone"`
Wechat string `json:"wechat"`
Name string `json:"name"`
UserID string `json:"userId"`
Remark string `json:"remark"`
Type string `json:"type" binding:"required"`
Phone string `json:"phone"`
Wechat string `json:"wechat"`
Name string `json:"name"`
UserID string `json:"userId"`
Remark string `json:"remark"`
CanHelp string `json:"canHelp"` // 资源对接:我能帮到你什么
NeedHelp string `json:"needHelp"` // 资源对接:我需要什么帮助
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "请提供手机号或微信号"})
@@ -83,7 +90,11 @@ func CKBJoin(c *gin.Context) {
"remark": body.Remark,
}
if body.Remark == "" {
params["remark"] = "用户通过创业实验APP申请" + ckbSourceMap[body.Type]
remark := "用户通过创业实验APP申请" + ckbSourceMap[body.Type]
if body.Type == "investor" && (body.CanHelp != "" || body.NeedHelp != "") {
remark = fmt.Sprintf("能帮:%s 需要:%s", body.CanHelp, body.NeedHelp)
}
params["remark"] = remark
}
if body.Phone != "" {
params["phone"] = body.Phone
@@ -96,14 +107,23 @@ func CKBJoin(c *gin.Context) {
}
params["apiKey"] = ckbAPIKey
params["sign"] = ckbSign(params, ckbAPIKey)
sourceData := map[string]interface{}{
"joinType": body.Type, "joinLabel": ckbSourceMap[body.Type], "userId": body.UserID,
"device": "webapp", "timestamp": time.Now().Format(time.RFC3339),
}
if body.Type == "investor" {
if body.CanHelp != "" {
sourceData["canHelp"] = body.CanHelp
}
if body.NeedHelp != "" {
sourceData["needHelp"] = body.NeedHelp
}
}
params["portrait"] = map[string]interface{}{
"type": 4, "source": 0,
"sourceData": map[string]interface{}{
"joinType": body.Type, "joinLabel": ckbSourceMap[body.Type], "userId": body.UserID,
"device": "webapp", "timestamp": time.Now().Format(time.RFC3339),
},
"remark": ckbSourceMap[body.Type] + "申请",
"uniqueId": "soul_" + body.Phone + body.Wechat + strconv.FormatInt(ts, 10),
"sourceData": sourceData,
"remark": ckbSourceMap[body.Type] + "申请",
"uniqueId": "soul_" + body.Phone + body.Wechat + strconv.FormatInt(ts, 10),
}
raw, _ := json.Marshal(params)
resp, err := http.Post(ckbAPIURL, "application/json", bytes.NewReader(raw))
@@ -127,7 +147,14 @@ func CKBJoin(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true, "message": msg, "data": result.Data})
return
}
c.JSON(http.StatusOK, gin.H{"success": false, "message": result.Message})
errMsg := result.Message
if errMsg == "" {
errMsg = "加入失败,请稍后重试"
}
// 打印 CKB 原始响应便于排查
fmt.Printf("[CKBJoin] 失败 type=%s wechat=%s code=%d message=%s raw=%s\n",
body.Type, body.Wechat, result.Code, result.Message, string(b))
c.JSON(http.StatusOK, gin.H{"success": false, "message": errMsg})
}
// CKBMatch POST /api/ckb/match

View File

@@ -88,8 +88,11 @@ func MatchUsers(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "缺少用户ID"})
return
}
// 只匹配已绑定微信或手机号的用户
var users []model.User
if err := database.DB().Where("id != ?", body.UserID).Order("created_at DESC").Limit(20).Find(&users).Error; err != nil || len(users) == 0 {
q := database.DB().Where("id != ?", body.UserID).
Where("((wechat_id IS NOT NULL AND wechat_id != '') OR (phone IS NOT NULL AND phone != ''))")
if err := q.Order("created_at DESC").Limit(20).Find(&users).Error; err != nil || len(users) == 0 {
c.JSON(http.StatusOK, gin.H{"success": false, "message": "暂无匹配用户", "data": nil})
return
}
@@ -114,9 +117,6 @@ func MatchUsers(c *gin.Context) {
phone := ""
if r.Phone != nil {
phone = *r.Phone
if len(phone) == 11 {
phone = phone[:3] + "****" + phone[7:]
}
}
intro := "来自Soul创业派对的伙伴"
matchLabels := map[string]string{"partner": "找伙伴", "investor": "资源对接", "mentor": "导师顾问", "team": "团队招募"}

View File

@@ -76,3 +76,13 @@
{"level":"debug","timestamp":"2026-02-10T12:08:49+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 403 Forbidden\r\nContent-Length: 171\r\nCache-Control: no-cache, must-revalidate\r\nConnection: keep-alive\r\nContent-Language: zh-CN\r\nContent-Type: application/json; charset=utf-8\r\nDate: Tue, 10 Feb 2026 04:08:49 GMT\r\nKeep-Alive: timeout=8\r\nRequest-Id: 08D1DEAACC06102B18FFD6BCA80120AA1928EBB404-268561072\r\nServer: nginx\r\nWechatpay-Nonce: 6c965e3c5aca952b9666dbccc6881923\r\nWechatpay-Serial: 5F2543BF58239A4EB68FA4433DF1438A88B34B16\r\nWechatpay-Signature: KKjTWimPKOSVdM/MzuPt3oAxtq3Cy2lr3ZqFXByMmgs3lovRianNEmtwmOi5EGtyo4TbdbUVpzObLUepZGfTIG7Cz8U1cnGLmqxfZxgSyRIatf5OVGYIh5RIwYrkqFdJaN/zcdjYOc73N8FWYn5+bgY51D6aD27AWbPwA7nYNJB4rKmH2QRR9ZuI1kuwDob2ezKWgzV8pkU3DxRSPP/G+BM/HINzurl04/bjAfAtst9JynlPfO61EmEEUCILSpBbKn9dSzEIq2YSz5SxIExv24fhUJ0pjcjvVZo+O0Ddx9vrkNDNSPXao83zqiZTrQkix2vDAEIc6r5SsLCyaGwaTA==\r\nWechatpay-Signature-Type: WECHATPAY2-SHA256-RSA2048\r\nWechatpay-Timestamp: 1770696529\r\nX-Content-Type-Options: nosniff\r\n\r\n{\"code\":\"NO_AUTH\",\"message\":\"当前商户号接入升级版本功能,暂不支持使用升级前功能,请在产品中心-商家转账-前往功能查看接口文档\"}"}
{"level":"debug","timestamp":"2026-02-10T14:30:44+08:00","caller":"kernel/baseClient.go:457","content":"POST https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills request header: { Content-Type:application/jsonAuthorization:WECHATPAY2-SHA256-RSA2048 mchid=\"1318592501\",nonce_str=\"tAslXtBASHF46eu8viT6eWrevb5s3amJ\",timestamp=\"1770705044\",serial_no=\"4A1DB62CD5C9BE0B6FC51C30621D6F99686E75C5\",signature=\"45mBO41rIGYDKEtV0wVTh5IjM9OsZNFFDcPpHCEXZin9ukqYHo8GXRlLR50gTYaETzoOry+kdI6Xe1aNpGoLLbeGFOw5Znj167BGrGPnfwyX87lAEvXbafrq7fpab+tVDHXJfLw/dnQ8q+Wy5/gszJx/YllSgyMgoIg+7gc3TDy8e6Ft/QtbbB8CLP4LVUvonG30OdVbspIDd6YpCsJSDQ58dM8Xb7sFEHaUv4bBVwu4U3sZ41muEXFH2JUgsVCT3AR+PgwXyTPeb+cNJyQ0RVAJ04/0fdPV3LszfKvjNJx5rtl05MQd5uS+Dh8JlFDXfHicnC4jG3EtAz1rT7crjw==\"Accept:*/*} request body:"}
{"level":"debug","timestamp":"2026-02-10T14:30:44+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 400 Bad Request\r\nContent-Length: 98\r\nCache-Control: no-cache, must-revalidate\r\nConnection: keep-alive\r\nContent-Language: zh-CN\r\nContent-Type: application/json; charset=utf-8\r\nDate: Tue, 10 Feb 2026 06:30:44 GMT\r\nKeep-Alive: timeout=8\r\nRequest-Id: 0894A1ABCC0610DF0318ECE7F8AF0120EE482884D103-268491067\r\nServer: nginx\r\nWechatpay-Nonce: 1edf81984af96eff23f05a173edee1a9\r\nWechatpay-Serial: 5F2543BF58239A4EB68FA4433DF1438A88B34B16\r\nWechatpay-Signature: sSpmhuIF5wtIHyiwwk7/4mjif3D6FadetjRTkamWXzuiTPp2Vmfo0je2ZKIC038nEqQpfC59ZuC2D6/xROJeAgbpuveTsNw+gRuw7ixMomRnu2ur5paxrelIxjxrStp66wjlbHRQgmsJyCag42ObZqrvJWA7SqPbyaYl3fmLGCv5I4uTiVLwTNmv2dg+9iMw6mk00A5sN99FXKDXIPrrTvKpyi7lbqoleDNzVBdG+DMhPh8Etjlr/QpHydjrTZ28plul6YtITAp8zYmEOMg/s0Iiz9Mp9ZCNDA2PPG1D/jZ2wpxqr1XMCnE6yZE3oKQqoXZZQr336LYjMxeQEh1lRA==\r\nWechatpay-Signature-Type: WECHATPAY2-SHA256-RSA2048\r\nWechatpay-Timestamp: 1770705044\r\nX-Content-Type-Options: nosniff\r\n\r\n{\"code\":\"INVALID_REQUEST\",\"message\":\"此IP地址不允许调用接口请按开发指引设置\"}"}
{"level":"debug","timestamp":"2026-02-11T15:24:51+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-11T15:24:51+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Wed, 11 Feb 2026 07:24:52 GMT\r\n\r\n{\"access_token\":\"101_rGBEywFQ8RzMuEbFWgtU8oYu6Dh5XR2GmwL5EUfPc1oCatASfWinC9ei7mYVYWAOXpKY0KLnwHNB3XAOlqu1eMxy99iEUFzxW0V8dT84peEIOYxzZjKqWpxPamEBZZaABAJHH\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-11T15:33:31+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=101_rGBEywFQ8RzMuEbFWgtU8oYu6Dh5XR2GmwL5EUfPc1oCatASfWinC9ei7mYVYWAOXpKY0KLnwHNB3XAOlqu1eMxy99iEUFzxW0V8dT84peEIOYxzZjKqWpxPamEBZZaABAJHH&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0c3dPKll2GXA9h4XdBol2lv2Hv2dPKlL&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-11T15:33:31+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Wed, 11 Feb 2026 07:33:32 GMT\r\n\r\n{\"session_key\":\"/BZGO5L50veBj7S7Jmt5KQ==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-11T15:34:32+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=101_rGBEywFQ8RzMuEbFWgtU8oYu6Dh5XR2GmwL5EUfPc1oCatASfWinC9ei7mYVYWAOXpKY0KLnwHNB3XAOlqu1eMxy99iEUFzxW0V8dT84peEIOYxzZjKqWpxPamEBZZaABAJHH&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0d3AGZGa1YadaL04jeJa1qd37z2AGZGO&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-11T15:34:32+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Wed, 11 Feb 2026 07:34:32 GMT\r\n\r\n{\"session_key\":\"79hxrJbW2eK1gDiqMBhZMg==\",\"openid\":\"ogpTW5fmXRGNpoUbXB3UEqnVe5Tg\"}"}
{"level":"debug","timestamp":"2026-02-11T15:36:10+08:00","caller":"kernel/accessToken.go:381","content":"GET https://api.weixin.qq.com/cgi-bin/token?appid=wxb8bbb2b10dec74aa&grant_type=client_credential&neededText=&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-11T15:36:10+08:00","caller":"kernel/accessToken.go:383","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 174\r\nConnection: keep-alive\r\nContent-Type: application/json; encoding=utf-8\r\nDate: Wed, 11 Feb 2026 07:36:11 GMT\r\n\r\n{\"access_token\":\"101_MiWs49YphSqT8fdzbbvWznN0pNKQ99O94IqbcNCL6FoMWAZG6t0v-D4xg37xDjsyGgttZm2qfQd1pg6C4za3yiJrKv8g7s8M1n_-biSvQq-zNg6WqUzq1zTv_HQVRQaACALHG\",\"expires_in\":7200}"}
{"level":"debug","timestamp":"2026-02-11T15:36:11+08:00","caller":"kernel/baseClient.go:457","content":"GET https://api.weixin.qq.com/sns/jscode2session?access_token=101_MiWs49YphSqT8fdzbbvWznN0pNKQ99O94IqbcNCL6FoMWAZG6t0v-D4xg37xDjsyGgttZm2qfQd1pg6C4za3yiJrKv8g7s8M1n_-biSvQq-zNg6WqUzq1zTv_HQVRQaACALHG&appid=wxb8bbb2b10dec74aa&grant_type=authorization_code&js_code=0a1alR000sNRQV1MJl400aJVgF3alR0q&secret=3c1fb1f63e6e052222bbcead9d07fe0c request header: { Accept:*/*} "}
{"level":"debug","timestamp":"2026-02-11T15:36:11+08:00","caller":"kernel/baseClient.go:459","content":"------------------response content:HTTP/1.1 200 OK\r\nContent-Length: 82\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nDate: Wed, 11 Feb 2026 07:36:11 GMT\r\n\r\n{\"session_key\":\"XL+GLsPRGyvEHUMFyzfbZg==\",\"openid\":\"ogpTW5a9exdEmEwqZsYywvgSpSQg\"}"}

1
tmp/build-errors.log Normal file
View File

@@ -0,0 +1 @@
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1