Merge branch 'yongxu-dev' into devlop

# Conflicts:
#	miniprogram/pages/profile-edit/profile-edit.js
#	miniprogram/pages/profile-edit/profile-edit.wxml
#	miniprogram/pages/settings/settings.js
#	miniprogram/utils/ruleEngine.js
#	soul-admin/src/pages/distribution/DistributionPage.tsx
#	soul-admin/src/pages/users/UsersPage.tsx
#	soul-api/.env.production
#	soul-api/.gitignore
#	soul-api/internal/handler/db_ckb_leads.go
#	soul-api/internal/handler/miniprogram.go
#	soul-api/internal/handler/referral.go
#	开发文档/1、需求/archive/链接人与事-存客宝同步-需求规划.md
#	开发文档/1、需求/archive/链接人与事-实现方案.md
This commit is contained in:
Alex-larget
2026-03-20 14:48:02 +08:00
247 changed files with 8990 additions and 6983 deletions

View File

@@ -1,8 +1,9 @@
/**
* Soul创业派对 - 设置页
* 卡若创业派对 - 设置页
* 账号绑定功能
*/
const app = getApp()
const { toAvatarPath } = require('../../utils/util.js')
Page({
data: {
@@ -29,7 +30,8 @@ Page({
// 绑定弹窗
showBindModal: false,
bindType: '', // phone | wechat | alipay
bindValue: ''
bindValue: '',
showPrivacyModal: false
},
onLoad() {
@@ -245,70 +247,101 @@ Page({
}
},
// 微信原生 chooseAvatar 回调
async onChooseAvatar(e) {
const tempAvatarUrl = e.detail?.avatarUrl
if (!tempAvatarUrl) return
wx.showLoading({ title: '上传中...', mask: true })
// 获取微信头像(新版授权)
async getWechatAvatar() {
try {
const uploadRes = await new Promise((resolve, reject) => {
wx.uploadFile({
url: app.globalData.baseUrl + '/api/miniprogram/upload',
filePath: tempAvatarUrl,
name: 'file',
formData: { folder: 'avatars' },
success: (uploadResult) => {
try {
const data = JSON.parse(uploadResult.data)
if (data.success) resolve(data)
else reject(new Error(data.error || '上传失败'))
} catch (err) {
reject(new Error('解析响应失败'))
const res = await wx.getUserProfile({
desc: '用于完善会员资料'
})
if (res.userInfo) {
const { nickName, avatarUrl: tempAvatarUrl } = res.userInfo
wx.showLoading({ title: '上传中...', mask: true })
// 1. 先上传图片到服务器
console.log('[Settings] 开始上传头像:', tempAvatarUrl)
const uploadRes = await new Promise((resolve, reject) => {
wx.uploadFile({
url: app.globalData.baseUrl + '/api/miniprogram/upload',
filePath: tempAvatarUrl,
name: 'file',
formData: {
folder: 'avatars'
},
success: (uploadResult) => {
try {
const data = JSON.parse(uploadResult.data)
if (data.success) {
resolve(data)
} else {
reject(new Error(data.error || '上传失败'))
}
} catch (err) {
reject(new Error('解析响应失败'))
}
},
fail: (err) => {
reject(err)
}
},
fail: reject
})
})
})
const rawUrl = uploadRes.data.url || ''
const avatarUrl = rawUrl.startsWith('http://') || rawUrl.startsWith('https://')
? rawUrl
: app.globalData.baseUrl + rawUrl
const nickname = this.data.userInfo?.nickname || app.globalData.userInfo?.nickname || ''
this.setData({
userInfo: {
...this.data.userInfo,
nickname,
avatar: avatarUrl
// 2. 获取上传后的完整URL显示用保存时只传路径
let avatarUrl = uploadRes.data?.url || uploadRes.url
if (avatarUrl && !avatarUrl.startsWith('http')) {
avatarUrl = app.globalData.baseUrl + avatarUrl
}
})
const userId = app.globalData.userInfo?.id
if (userId) {
await app.request('/api/miniprogram/user/profile', {
method: 'POST',
data: { userId, nickname, avatar: avatarUrl }
console.log('[Settings] 头像上传成功:', avatarUrl)
// 3. 更新本地
this.setData({
userInfo: {
...this.data.userInfo,
nickname: nickName,
avatar: avatarUrl
}
})
// 4. 同步到服务器数据库(只保存路径,不含域名)
const userId = app.globalData.userInfo?.id
if (userId) {
await app.request('/api/miniprogram/user/profile', {
method: 'POST',
data: { userId, nickname: nickName, avatar: toAvatarPath(avatarUrl) }
})
}
// 5. 更新全局
if (app.globalData.userInfo) {
app.globalData.userInfo.nickname = nickName
app.globalData.userInfo.avatar = avatarUrl
wx.setStorageSync('userInfo', app.globalData.userInfo)
}
wx.hideLoading()
wx.showToast({ title: '头像更新成功', icon: 'success' })
}
if (app.globalData.userInfo) {
app.globalData.userInfo.avatar = avatarUrl
wx.setStorageSync('userInfo', app.globalData.userInfo)
}
wx.hideLoading()
wx.showToast({ title: '头像更新成功', icon: 'success' })
} catch (e) {
wx.hideLoading()
console.error('[Settings] 更新头像失败:', e)
wx.showToast({
title: e.message || '上传失败,请重试',
icon: 'none'
console.error('[Settings] 获取头像失败:', e)
wx.showToast({
title: e.message || '获取头像失败',
icon: 'none'
})
}
},
// 微信隐私协议同意getPhoneNumber 需先同意)
onAgreePrivacyForPhone() {
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.setData({ showPrivacyModal: false })
},
// 一键获取微信手机号button组件回调
async onGetPhoneNumber(e) {
console.log('[Settings] 获取手机号回调:', e.detail)
@@ -369,6 +402,11 @@ Page({
this.setData({ showBindModal: false })
},
// 跳转账户密码登录页(开发)
goToDevLogin() {
wx.navigateTo({ url: '/pages/dev-login/dev-login' })
},
// 打开切换账号弹窗(开发)
openSwitchAccountModal() {
this.setData({
@@ -488,13 +526,13 @@ Page({
onShareAppMessage() {
const ref = app.getMyReferralCode()
return {
title: 'Soul创业派对 - 设置',
title: '卡若创业派对 - 设置',
path: ref ? `/pages/settings/settings?ref=${ref}` : '/pages/settings/settings'
}
},
onShareTimeline() {
const ref = app.getMyReferralCode()
return { title: 'Soul创业派对 - 设置', query: ref ? `ref=${ref}` : '' }
return { title: '卡若创业派对 - 设置', query: ref ? `ref=${ref}` : '' }
}
})

View File

@@ -32,11 +32,15 @@
</view>
<view class="bind-right">
<icon wx:if="{{phoneNumber}}" name="check" size="36" color="#34C759" customClass="bind-check"></icon>
<button wx:else class="get-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
<button wx:else id="agree-settings-phone-btn" class="get-phone-btn" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="onGetPhoneNumber" bindagreeprivacyauthorization="onAgreePrivacyForPhone">
一键获取
</button>
</view>
</view>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="onAgreePrivacyForPhone">同意</button>
</view>
<!-- 微信号 - 简化输入 -->
<view class="bind-item">
@@ -117,6 +121,13 @@
<text class="dev-switch-desc">输入 userId 切换为其他账号调试</text>
</view>
</view>
<view class="dev-switch-card" wx:if="{{isDevMode}}" bindtap="goToDevLogin">
<view class="dev-switch-inner">
<icon name="smartphone" size="40" color="#8e8e93" customClass="dev-switch-icon"></icon>
<text class="dev-switch-text">账户密码登录</text>
<text class="dev-switch-desc">输入对方手机号登录,密码可留空</text>
</view>
</view>
<view class="logout-btn" wx:if="{{isLoggedIn}}" bindtap="handleLogout">退出登录</view>
</view>

View File

@@ -49,6 +49,10 @@
line-height: normal;
}
.get-phone-btn::after { border: none; }
.privacy-wechat-row { margin: 24rpx 0; padding: 24rpx; background: rgba(0,206,209,0.1); border-radius: 16rpx; }
.privacy-wechat-desc { display: block; font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 16rpx; }
.privacy-agree-btn { width: 100%; padding: 20rpx; background: #07C160; color: #fff; font-size: 28rpx; border-radius: 16rpx; border: none; }
.privacy-agree-btn::after { border: none; }
/* 自动提现卡片 */
.auto-withdraw-card { margin-top: 24rpx; }