2026-01-21 15:49:12 +08:00
|
|
|
|
/**
|
2026-01-25 19:37:59 +08:00
|
|
|
|
* Soul创业派对 - 我的页面
|
2026-01-21 15:49:12 +08:00
|
|
|
|
* 开发: 卡若
|
2026-02-24 14:35:58 +08:00
|
|
|
|
* 技术支持: 存客宝
|
2026-01-21 15:49:12 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
2026-01-14 12:50:00 +08:00
|
|
|
|
const app = getApp()
|
|
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 系统信息
|
2026-01-21 15:49:12 +08:00
|
|
|
|
statusBarHeight: 44,
|
|
|
|
|
|
navBarHeight: 88,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 用户状态
|
2026-01-21 15:49:12 +08:00
|
|
|
|
isLoggedIn: false,
|
|
|
|
|
|
userInfo: null,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 统计数据
|
2026-01-21 15:49:12 +08:00
|
|
|
|
totalSections: 62,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
readCount: 0,
|
2026-01-21 15:49:12 +08:00
|
|
|
|
referralCount: 0,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
earnings: '-',
|
|
|
|
|
|
pendingEarnings: '-',
|
|
|
|
|
|
earningsLoading: true,
|
|
|
|
|
|
earningsRefreshing: false,
|
|
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
// 阅读统计
|
|
|
|
|
|
totalReadTime: 0,
|
|
|
|
|
|
matchHistory: 0,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 最近阅读
|
2026-01-21 15:49:12 +08:00
|
|
|
|
recentChapters: [],
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 功能配置
|
|
|
|
|
|
matchEnabled: false,
|
|
|
|
|
|
|
|
|
|
|
|
// VIP状态
|
|
|
|
|
|
isVip: false,
|
|
|
|
|
|
vipExpireDate: '',
|
|
|
|
|
|
|
|
|
|
|
|
// 待确认收款
|
|
|
|
|
|
pendingConfirmList: [],
|
|
|
|
|
|
withdrawMchId: '',
|
|
|
|
|
|
withdrawAppId: '',
|
|
|
|
|
|
|
|
|
|
|
|
// 未登录假资料(展示用)
|
|
|
|
|
|
guestNickname: '游客',
|
|
|
|
|
|
guestAvatar: '',
|
|
|
|
|
|
|
|
|
|
|
|
// 登录弹窗
|
2026-01-21 15:49:12 +08:00
|
|
|
|
showLoginModal: false,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
isLoggingIn: false,
|
|
|
|
|
|
// 用户须主动勾选同意协议(审核要求:不得默认同意)
|
|
|
|
|
|
agreeProtocol: false,
|
|
|
|
|
|
|
|
|
|
|
|
// 修改昵称弹窗
|
|
|
|
|
|
showNicknameModal: false,
|
2026-02-28 15:16:23 +08:00
|
|
|
|
editingNickname: '',
|
|
|
|
|
|
|
2026-03-03 11:12:56 +08:00
|
|
|
|
// 头像弹窗(含 chooseAvatar 按钮,必须用户点击才可获取微信头像)
|
|
|
|
|
|
showAvatarModal: false,
|
|
|
|
|
|
|
2026-02-28 15:16:23 +08:00
|
|
|
|
// 手机/微信号弹窗(stitch_soul comprehensive_profile_editor_v1_2)
|
|
|
|
|
|
showContactModal: false,
|
|
|
|
|
|
contactPhone: '',
|
|
|
|
|
|
contactWechat: '',
|
|
|
|
|
|
contactSaving: false,
|
|
|
|
|
|
pendingWithdraw: false,
|
2026-01-14 12:50:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
onLoad() {
|
2026-02-27 14:22:58 +08:00
|
|
|
|
wx.showShareMenu({ withShareTimeline: true })
|
2026-01-21 15:49:12 +08:00
|
|
|
|
this.setData({
|
|
|
|
|
|
statusBarHeight: app.globalData.statusBarHeight,
|
|
|
|
|
|
navBarHeight: app.globalData.navBarHeight
|
|
|
|
|
|
})
|
2026-02-24 14:35:58 +08:00
|
|
|
|
this.loadFeatureConfig()
|
2026-01-21 15:49:12 +08:00
|
|
|
|
this.initUserStatus()
|
2026-01-14 12:50:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShow() {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 设置TabBar选中状态(根据 matchEnabled 动态设置)
|
2026-01-21 15:49:12 +08:00
|
|
|
|
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
const tabBar = this.getTabBar()
|
|
|
|
|
|
if (tabBar.updateSelected) {
|
|
|
|
|
|
tabBar.updateSelected()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const selected = tabBar.data.matchEnabled ? 3 : 2
|
|
|
|
|
|
tabBar.setData({ selected })
|
|
|
|
|
|
}
|
2026-01-21 15:49:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
this.initUserStatus()
|
2026-01-14 12:50:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
async loadFeatureConfig() {
|
2026-02-23 14:07:41 +08:00
|
|
|
|
try {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
const res = await app.request('/api/miniprogram/config')
|
|
|
|
|
|
const features = (res && res.features) || (res && res.data && res.data.features) || {}
|
|
|
|
|
|
this.setData({ matchEnabled: features.matchEnabled === true })
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log('加载功能配置失败:', error)
|
|
|
|
|
|
this.setData({ matchEnabled: false })
|
2026-02-23 14:07:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
// 初始化用户状态
|
2026-02-24 14:35:58 +08:00
|
|
|
|
initUserStatus() {
|
|
|
|
|
|
const { isLoggedIn, userInfo } = app.globalData
|
|
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
if (isLoggedIn && userInfo) {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
const readIds = app.globalData.readSectionIds || []
|
|
|
|
|
|
const recentList = readIds.slice(-5).reverse().map(id => ({
|
2026-02-28 10:19:46 +08:00
|
|
|
|
id,
|
|
|
|
|
|
mid: app.getSectionMid(id),
|
2026-02-24 14:35:58 +08:00
|
|
|
|
title: `章节 ${id}`
|
2026-01-21 15:49:12 +08:00
|
|
|
|
}))
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
2026-01-29 11:20:12 +08:00
|
|
|
|
const userId = userInfo.id || ''
|
|
|
|
|
|
const userIdShort = userId.length > 20 ? userId.slice(0, 10) + '...' + userId.slice(-6) : userId
|
2026-01-29 15:50:45 +08:00
|
|
|
|
const userWechat = wx.getStorageSync('user_wechat') || userInfo.wechat || ''
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 先设基础信息;收益由 loadMyEarnings 专用接口拉取,加载前用 - 占位
|
2026-01-21 15:49:12 +08:00
|
|
|
|
this.setData({
|
|
|
|
|
|
isLoggedIn: true,
|
|
|
|
|
|
userInfo,
|
2026-01-29 11:20:12 +08:00
|
|
|
|
userIdShort,
|
2026-01-29 15:50:45 +08:00
|
|
|
|
userWechat,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
readCount: Math.min(app.getReadCount(), this.data.totalSections || 62),
|
2026-01-21 15:49:12 +08:00
|
|
|
|
referralCount: userInfo.referralCount || 0,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
earnings: '-',
|
|
|
|
|
|
pendingEarnings: '-',
|
|
|
|
|
|
earningsLoading: true,
|
2026-01-21 15:49:12 +08:00
|
|
|
|
recentChapters: recentList,
|
|
|
|
|
|
totalReadTime: Math.floor(Math.random() * 200) + 50
|
|
|
|
|
|
})
|
2026-02-24 14:35:58 +08:00
|
|
|
|
this.loadMyEarnings()
|
|
|
|
|
|
this.loadPendingConfirm()
|
|
|
|
|
|
this.loadVipStatus()
|
2026-01-14 12:50:00 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
this.setData({
|
2026-02-24 14:35:58 +08:00
|
|
|
|
isLoggedIn: false,
|
|
|
|
|
|
userInfo: null,
|
|
|
|
|
|
userIdShort: '',
|
|
|
|
|
|
readCount: app.getReadCount(),
|
|
|
|
|
|
referralCount: 0,
|
|
|
|
|
|
earnings: '-',
|
|
|
|
|
|
pendingEarnings: '-',
|
|
|
|
|
|
earningsLoading: false,
|
|
|
|
|
|
recentChapters: []
|
2026-01-14 12:50:00 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-02-23 14:07:41 +08:00
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 拉取待确认收款列表(用于「确认收款」按钮)
|
|
|
|
|
|
async loadPendingConfirm() {
|
|
|
|
|
|
const userInfo = app.globalData.userInfo
|
|
|
|
|
|
if (!app.globalData.isLoggedIn || !userInfo || !userInfo.id) return
|
2026-02-23 14:07:41 +08:00
|
|
|
|
try {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
const res = await app.request({ url: '/api/miniprogram/withdraw/pending-confirm?userId=' + userInfo.id, silent: true })
|
|
|
|
|
|
if (res && res.success && res.data) {
|
|
|
|
|
|
const list = (res.data.list || []).map(item => ({
|
|
|
|
|
|
id: item.id,
|
|
|
|
|
|
amount: (item.amount || 0).toFixed(2),
|
|
|
|
|
|
package: item.package,
|
|
|
|
|
|
createdAt: (item.createdAt ?? item.created_at) ? this.formatDateMy(item.createdAt ?? item.created_at) : '--'
|
|
|
|
|
|
}))
|
2026-02-23 14:07:41 +08:00
|
|
|
|
this.setData({
|
2026-02-24 14:35:58 +08:00
|
|
|
|
pendingConfirmList: list,
|
|
|
|
|
|
withdrawMchId: res.data.mchId ?? res.data.mch_id ?? '',
|
|
|
|
|
|
withdrawAppId: res.data.appId ?? res.data.app_id ?? ''
|
2026-02-23 14:07:41 +08:00
|
|
|
|
})
|
2026-02-24 14:35:58 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
this.setData({ pendingConfirmList: [], withdrawMchId: '', withdrawAppId: '' })
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
this.setData({ pendingConfirmList: [] })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
formatDateMy(dateStr) {
|
|
|
|
|
|
if (!dateStr) return '--'
|
|
|
|
|
|
const d = new Date(dateStr)
|
|
|
|
|
|
const m = (d.getMonth() + 1).toString().padStart(2, '0')
|
|
|
|
|
|
const day = d.getDate().toString().padStart(2, '0')
|
|
|
|
|
|
return `${m}-${day}`
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 确认收款:有 package 时调起微信收款页,成功后记录;无 package 时仅调用后端记录「已确认收款」
|
|
|
|
|
|
async confirmReceive(e) {
|
|
|
|
|
|
const index = e.currentTarget.dataset.index
|
|
|
|
|
|
const id = e.currentTarget.dataset.id
|
|
|
|
|
|
const list = this.data.pendingConfirmList || []
|
|
|
|
|
|
let item = (typeof index === 'number' || (index !== undefined && index !== '')) ? list[index] : null
|
|
|
|
|
|
if (!item && id) item = list.find(x => x.id === id) || null
|
|
|
|
|
|
if (!item) {
|
|
|
|
|
|
wx.showToast({ title: '请稍后刷新再试', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const mchId = this.data.withdrawMchId
|
|
|
|
|
|
const appId = this.data.withdrawAppId
|
|
|
|
|
|
const hasPackage = item.package && mchId && appId && wx.canIUse('requestMerchantTransfer')
|
|
|
|
|
|
|
|
|
|
|
|
const recordConfirmReceived = async () => {
|
|
|
|
|
|
const userInfo = app.globalData.userInfo
|
|
|
|
|
|
if (userInfo && userInfo.id) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await app.request({
|
|
|
|
|
|
url: '/api/miniprogram/withdraw/confirm-received',
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: { withdrawalId: item.id, userId: userInfo.id }
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (e) { /* 仅记录,不影响前端展示 */ }
|
|
|
|
|
|
}
|
|
|
|
|
|
const newList = list.filter(x => x.id !== item.id)
|
|
|
|
|
|
this.setData({ pendingConfirmList: newList })
|
|
|
|
|
|
this.loadPendingConfirm()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (hasPackage) {
|
|
|
|
|
|
wx.showLoading({ title: '调起收款...', mask: true })
|
|
|
|
|
|
wx.requestMerchantTransfer({
|
|
|
|
|
|
mchId,
|
|
|
|
|
|
appId,
|
|
|
|
|
|
package: item.package,
|
|
|
|
|
|
success: async () => {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: '收款成功', icon: 'success' })
|
|
|
|
|
|
await recordConfirmReceived()
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
const msg = (err.errMsg || '').includes('cancel') ? '已取消' : (err.errMsg || '收款失败')
|
|
|
|
|
|
wx.showToast({ title: msg, icon: 'none' })
|
|
|
|
|
|
},
|
|
|
|
|
|
complete: () => { wx.hideLoading() }
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 无 package 时仅记录「确认已收款」(当前直接打款无 package,用户点按钮即记录)
|
|
|
|
|
|
wx.showLoading({ title: '提交中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
await recordConfirmReceived()
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: '已记录确认收款', icon: 'success' })
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: (e && e.message) || '操作失败', icon: 'none' })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 专用接口:拉取「我的收益」卡片数据(累计、可提现、推荐人数)
|
|
|
|
|
|
async loadMyEarnings() {
|
|
|
|
|
|
const userInfo = app.globalData.userInfo
|
|
|
|
|
|
if (!app.globalData.isLoggedIn || !userInfo || !userInfo.id) {
|
|
|
|
|
|
this.setData({ earningsLoading: false })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const formatMoney = (num) => (typeof num === 'number' ? num.toFixed(2) : '0.00')
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await app.request({ url: '/api/miniprogram/earnings?userId=' + userInfo.id, silent: true })
|
|
|
|
|
|
if (!res || !res.success || !res.data) {
|
|
|
|
|
|
this.setData({ earningsLoading: false, earnings: '0.00', pendingEarnings: '0.00' })
|
|
|
|
|
|
return
|
2026-02-23 14:07:41 +08:00
|
|
|
|
}
|
2026-02-24 14:35:58 +08:00
|
|
|
|
const d = res.data
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
earnings: formatMoney(d.totalCommission),
|
|
|
|
|
|
pendingEarnings: formatMoney(d.availableEarnings),
|
|
|
|
|
|
referralCount: d.referralCount ?? this.data.referralCount,
|
|
|
|
|
|
earningsLoading: false,
|
|
|
|
|
|
earningsRefreshing: false
|
|
|
|
|
|
})
|
2026-02-23 14:07:41 +08:00
|
|
|
|
} catch (e) {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
console.log('[My] 拉取我的收益失败:', e && e.message)
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
earningsLoading: false,
|
|
|
|
|
|
earningsRefreshing: false,
|
|
|
|
|
|
earnings: '0.00',
|
|
|
|
|
|
pendingEarnings: '0.00'
|
|
|
|
|
|
})
|
2026-02-23 14:07:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 点击刷新图标:刷新我的收益
|
|
|
|
|
|
async refreshEarnings() {
|
|
|
|
|
|
if (!this.data.isLoggedIn) return
|
|
|
|
|
|
if (this.data.earningsRefreshing) return
|
|
|
|
|
|
this.setData({ earningsRefreshing: true })
|
|
|
|
|
|
wx.showToast({ title: '刷新中...', icon: 'loading', duration: 2000 })
|
|
|
|
|
|
await this.loadMyEarnings()
|
|
|
|
|
|
wx.showToast({ title: '已刷新', icon: 'success' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-03 11:12:56 +08:00
|
|
|
|
// 微信原生获取头像(button open-type="chooseAvatar" 回调,真正获取微信头像)
|
2026-01-29 12:44:29 +08:00
|
|
|
|
async onChooseAvatar(e) {
|
2026-03-03 11:12:56 +08:00
|
|
|
|
const tempAvatarUrl = e.detail?.avatarUrl
|
|
|
|
|
|
this.setData({ showAvatarModal: false })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
if (!tempAvatarUrl) return
|
|
|
|
|
|
wx.showLoading({ title: '上传中...', mask: true })
|
|
|
|
|
|
|
2026-01-29 12:44:29 +08:00
|
|
|
|
try {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 1. 先上传图片到服务器
|
|
|
|
|
|
console.log('[My] 开始上传头像:', 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: (res) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = JSON.parse(res.data)
|
|
|
|
|
|
if (data.success) {
|
|
|
|
|
|
resolve(data)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
reject(new Error(data.error || '上传失败'))
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
reject(new Error('解析响应失败'))
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
reject(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 获取上传后的完整URL
|
|
|
|
|
|
const avatarUrl = app.globalData.baseUrl + uploadRes.data.url
|
|
|
|
|
|
console.log('[My] 头像上传成功:', avatarUrl)
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 更新本地头像
|
2026-01-29 12:44:29 +08:00
|
|
|
|
const userInfo = this.data.userInfo
|
|
|
|
|
|
userInfo.avatar = avatarUrl
|
|
|
|
|
|
this.setData({ userInfo })
|
|
|
|
|
|
app.globalData.userInfo = userInfo
|
|
|
|
|
|
wx.setStorageSync('userInfo', userInfo)
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 4. 同步到服务器数据库
|
|
|
|
|
|
await app.request('/api/miniprogram/user/update', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: { userId: userInfo.id, avatar: avatarUrl }
|
2026-01-29 12:44:29 +08:00
|
|
|
|
})
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
2026-01-29 12:44:29 +08:00
|
|
|
|
wx.hideLoading()
|
2026-02-24 14:35:58 +08:00
|
|
|
|
wx.showToast({ title: '头像更新成功', icon: 'success' })
|
|
|
|
|
|
|
2026-01-29 12:44:29 +08:00
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.hideLoading()
|
2026-02-24 14:35:58 +08:00
|
|
|
|
console.error('[My] 上传头像失败:', e)
|
|
|
|
|
|
wx.showToast({
|
|
|
|
|
|
title: e.message || '上传失败,请重试',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
2026-01-29 12:44:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 微信原生获取昵称回调(针对 input type="nickname" 的 bindblur 或 bindchange)
|
|
|
|
|
|
async handleNicknameChange(nickname) {
|
|
|
|
|
|
if (!nickname || nickname === this.data.userInfo?.nickname) return
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const userInfo = this.data.userInfo
|
|
|
|
|
|
userInfo.nickname = nickname
|
|
|
|
|
|
this.setData({ userInfo })
|
|
|
|
|
|
app.globalData.userInfo = userInfo
|
|
|
|
|
|
wx.setStorageSync('userInfo', userInfo)
|
|
|
|
|
|
|
|
|
|
|
|
// 同步到服务器
|
|
|
|
|
|
await app.request('/api/miniprogram/user/update', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: { userId: userInfo.id, nickname }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
wx.showToast({ title: '昵称已更新', icon: 'success' })
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('[My] 同步昵称失败:', e)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 打开昵称修改弹窗
|
2026-01-29 11:20:12 +08:00
|
|
|
|
editNickname() {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
this.setData({
|
|
|
|
|
|
showNicknameModal: true,
|
|
|
|
|
|
editingNickname: this.data.userInfo?.nickname || ''
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭昵称弹窗
|
|
|
|
|
|
closeNicknameModal() {
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
showNicknameModal: false,
|
|
|
|
|
|
editingNickname: ''
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 阻止事件冒泡
|
|
|
|
|
|
stopPropagation() {},
|
|
|
|
|
|
|
|
|
|
|
|
// 昵称输入实时更新
|
|
|
|
|
|
onNicknameInput(e) {
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
editingNickname: e.detail.value
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 昵称变化(微信自动填充时触发)
|
|
|
|
|
|
onNicknameChange(e) {
|
|
|
|
|
|
const nickname = e.detail.value
|
|
|
|
|
|
console.log('[My] 昵称已自动填充:', nickname)
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
editingNickname: nickname
|
|
|
|
|
|
})
|
|
|
|
|
|
// 自动填充时也尝试直接同步
|
|
|
|
|
|
this.handleNicknameChange(nickname)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 确认修改昵称
|
|
|
|
|
|
async confirmNickname() {
|
|
|
|
|
|
const newNickname = this.data.editingNickname.trim()
|
|
|
|
|
|
|
|
|
|
|
|
if (!newNickname) {
|
|
|
|
|
|
wx.showToast({ title: '昵称不能为空', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (newNickname.length < 1 || newNickname.length > 20) {
|
|
|
|
|
|
wx.showToast({ title: '昵称1-20个字符', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭弹窗
|
|
|
|
|
|
this.closeNicknameModal()
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载
|
|
|
|
|
|
wx.showLoading({ title: '更新中...', mask: true })
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 1. 同步到服务器
|
|
|
|
|
|
const res = await app.request('/api/miniprogram/user/update', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: {
|
|
|
|
|
|
userId: this.data.userInfo.id,
|
|
|
|
|
|
nickname: newNickname
|
2026-01-29 11:20:12 +08:00
|
|
|
|
}
|
2026-02-24 14:35:58 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if (res && res.success) {
|
|
|
|
|
|
// 2. 更新本地状态
|
|
|
|
|
|
const userInfo = this.data.userInfo
|
|
|
|
|
|
userInfo.nickname = newNickname
|
|
|
|
|
|
this.setData({ userInfo })
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 更新全局和缓存
|
|
|
|
|
|
app.globalData.userInfo = userInfo
|
|
|
|
|
|
wx.setStorageSync('userInfo', userInfo)
|
|
|
|
|
|
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: '昵称已修改', icon: 'success' })
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error(res?.message || '更新失败')
|
2026-01-29 11:20:12 +08:00
|
|
|
|
}
|
2026-02-24 14:35:58 +08:00
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
console.error('[My] 修改昵称失败:', e)
|
|
|
|
|
|
wx.showToast({ title: '修改失败,请重试', icon: 'none' })
|
|
|
|
|
|
}
|
2026-01-29 11:20:12 +08:00
|
|
|
|
},
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 复制用户ID
|
2026-01-29 12:18:51 +08:00
|
|
|
|
copyUserId() {
|
|
|
|
|
|
const userId = this.data.userInfo?.id || ''
|
2026-02-24 14:35:58 +08:00
|
|
|
|
if (!userId) {
|
|
|
|
|
|
wx.showToast({ title: '暂无ID', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
wx.setClipboardData({
|
|
|
|
|
|
data: userId,
|
|
|
|
|
|
success: () => {
|
|
|
|
|
|
wx.showToast({ title: 'ID已复制', icon: 'success' })
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2026-01-29 12:18:51 +08:00
|
|
|
|
},
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 切换Tab
|
|
|
|
|
|
switchTab(e) {
|
|
|
|
|
|
const tab = e.currentTarget.dataset.tab
|
|
|
|
|
|
this.setData({ activeTab: tab })
|
|
|
|
|
|
},
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 显示登录弹窗(每次打开时协议未勾选,符合审核要求)
|
|
|
|
|
|
showLogin() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
this.setData({ showLoginModal: true, agreeProtocol: false })
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('[My] showLogin error:', e)
|
|
|
|
|
|
this.setData({ showLoginModal: true })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 切换协议勾选(用户主动勾选,非默认同意)
|
|
|
|
|
|
toggleAgree() {
|
|
|
|
|
|
this.setData({ agreeProtocol: !this.data.agreeProtocol })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 打开用户协议页(审核要求:点击《用户协议》需有响应)
|
|
|
|
|
|
openUserProtocol() {
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/agreement/agreement' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 打开隐私政策页(审核要求:点击《隐私政策》需有响应)
|
|
|
|
|
|
openPrivacy() {
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/privacy/privacy' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭登录弹窗
|
|
|
|
|
|
closeLoginModal() {
|
|
|
|
|
|
if (this.data.isLoggingIn) return
|
|
|
|
|
|
this.setData({ showLoginModal: false })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 微信登录(须已勾选同意协议,且做好错误处理避免审核报错)
|
2026-01-21 15:49:12 +08:00
|
|
|
|
async handleWechatLogin() {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
if (!this.data.agreeProtocol) {
|
|
|
|
|
|
wx.showToast({ title: '请先阅读并同意用户协议和隐私政策', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-01-21 15:49:12 +08:00
|
|
|
|
this.setData({ isLoggingIn: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const result = await app.login()
|
|
|
|
|
|
if (result) {
|
|
|
|
|
|
this.initUserStatus()
|
2026-02-24 14:35:58 +08:00
|
|
|
|
this.setData({ showLoginModal: false, agreeProtocol: false })
|
2026-01-21 15:49:12 +08:00
|
|
|
|
wx.showToast({ title: '登录成功', icon: 'success' })
|
2026-01-14 12:50:00 +08:00
|
|
|
|
} else {
|
2026-01-21 15:49:12 +08:00
|
|
|
|
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
2026-01-14 12:50:00 +08:00
|
|
|
|
}
|
2026-01-21 15:49:12 +08:00
|
|
|
|
} catch (e) {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
console.error('[My] 微信登录错误:', e)
|
2026-01-21 15:49:12 +08:00
|
|
|
|
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
this.setData({ isLoggingIn: false })
|
|
|
|
|
|
}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 手机号登录(需要用户授权)
|
2026-01-21 15:49:12 +08:00
|
|
|
|
async handlePhoneLogin(e) {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 检查是否有授权code
|
|
|
|
|
|
if (!e.detail.code) {
|
|
|
|
|
|
// 用户拒绝授权或获取失败,尝试使用微信登录
|
|
|
|
|
|
console.log('手机号授权失败,尝试微信登录')
|
|
|
|
|
|
return this.handleWechatLogin()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
this.setData({ isLoggingIn: true })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
try {
|
|
|
|
|
|
const result = await app.loginWithPhone(e.detail.code)
|
|
|
|
|
|
if (result) {
|
|
|
|
|
|
this.initUserStatus()
|
|
|
|
|
|
this.setData({ showLoginModal: false })
|
|
|
|
|
|
wx.showToast({ title: '登录成功', icon: 'success' })
|
|
|
|
|
|
} else {
|
|
|
|
|
|
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
2026-01-14 12:50:00 +08:00
|
|
|
|
}
|
2026-01-21 15:49:12 +08:00
|
|
|
|
} catch (e) {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
console.error('手机号登录错误:', e)
|
2026-01-21 15:49:12 +08:00
|
|
|
|
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
this.setData({ isLoggingIn: false })
|
|
|
|
|
|
}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 点击菜单
|
2026-01-21 15:49:12 +08:00
|
|
|
|
handleMenuTap(e) {
|
|
|
|
|
|
const id = e.currentTarget.dataset.id
|
2026-02-24 14:35:58 +08:00
|
|
|
|
|
|
|
|
|
|
if (!this.data.isLoggedIn && id !== 'about') {
|
|
|
|
|
|
this.showLogin()
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const routes = {
|
|
|
|
|
|
orders: '/pages/purchases/purchases',
|
|
|
|
|
|
referral: '/pages/referral/referral',
|
|
|
|
|
|
withdrawRecords: '/pages/withdraw-records/withdraw-records',
|
|
|
|
|
|
about: '/pages/about/about',
|
|
|
|
|
|
settings: '/pages/settings/settings'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (routes[id]) {
|
|
|
|
|
|
wx.navigateTo({ url: routes[id] })
|
|
|
|
|
|
}
|
2026-02-23 14:07:41 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-28 10:19:46 +08:00
|
|
|
|
// 跳转到阅读页(优先传 mid,与分享逻辑一致)
|
2026-02-24 14:35:58 +08:00
|
|
|
|
goToRead(e) {
|
|
|
|
|
|
const id = e.currentTarget.dataset.id
|
2026-02-28 10:19:46 +08:00
|
|
|
|
const mid = e.currentTarget.dataset.mid || app.getSectionMid(id)
|
|
|
|
|
|
const q = mid ? `mid=${mid}` : `id=${id}`
|
|
|
|
|
|
wx.navigateTo({ url: `/pages/read/read?${q}` })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到目录
|
|
|
|
|
|
goToChapters() {
|
|
|
|
|
|
wx.switchTab({ url: '/pages/chapters/chapters' })
|
2026-01-14 12:50:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 跳转到关于页
|
|
|
|
|
|
goToAbout() {
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/about/about' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到匹配
|
|
|
|
|
|
goToMatch() {
|
|
|
|
|
|
wx.switchTab({ url: '/pages/match/match' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到推广中心
|
|
|
|
|
|
goToReferral() {
|
|
|
|
|
|
if (!this.data.isLoggedIn) {
|
|
|
|
|
|
this.showLogin()
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/referral/referral' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到找伙伴页面
|
|
|
|
|
|
goToMatch() {
|
|
|
|
|
|
wx.switchTab({ url: '/pages/match/match' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 退出登录
|
|
|
|
|
|
handleLogout() {
|
2026-02-21 14:04:55 +08:00
|
|
|
|
wx.showModal({
|
2026-02-24 14:35:58 +08:00
|
|
|
|
title: '退出登录',
|
|
|
|
|
|
content: '确定要退出登录吗?',
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
app.logout()
|
|
|
|
|
|
this.initUserStatus()
|
|
|
|
|
|
wx.showToast({ title: '已退出登录', icon: 'success' })
|
2026-02-21 14:04:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// VIP状态查询
|
|
|
|
|
|
async loadVipStatus() {
|
|
|
|
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
|
|
if (!userId) return
|
|
|
|
|
|
try {
|
2026-02-25 11:50:07 +08:00
|
|
|
|
const res = await app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
if (res?.success) {
|
|
|
|
|
|
this.setData({ isVip: res.data?.isVip, vipExpireDate: res.data?.expireDate || '' })
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) { console.log('[My] VIP查询失败', e) }
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-03 11:12:56 +08:00
|
|
|
|
// 头像点击:已登录弹出选项(微信头像 / 相册 / VIP)
|
2026-02-24 14:35:58 +08:00
|
|
|
|
onAvatarTap() {
|
|
|
|
|
|
if (!this.data.isLoggedIn) { this.showLogin(); return }
|
|
|
|
|
|
wx.showActionSheet({
|
2026-03-03 11:12:56 +08:00
|
|
|
|
itemList: ['获取微信头像', '从相册选择', '开通/管理VIP'],
|
2026-02-21 14:04:55 +08:00
|
|
|
|
success: (res) => {
|
2026-03-03 11:12:56 +08:00
|
|
|
|
if (res.tapIndex === 0) this.setData({ showAvatarModal: true })
|
|
|
|
|
|
if (res.tapIndex === 1) this.chooseAvatarFromAlbum()
|
|
|
|
|
|
if (res.tapIndex === 2) this.goToVip()
|
2026-02-21 14:04:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-03 11:12:56 +08:00
|
|
|
|
closeAvatarModal() {
|
|
|
|
|
|
this.setData({ showAvatarModal: false })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 从相册/相机选择(自定义图片)
|
|
|
|
|
|
chooseAvatarFromAlbum() {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
wx.chooseMedia({
|
|
|
|
|
|
count: 1, mediaType: ['image'], sourceType: ['album', 'camera'],
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
const tempPath = res.tempFiles[0].tempFilePath
|
2026-03-03 11:12:56 +08:00
|
|
|
|
wx.showLoading({ title: '上传中...', mask: true })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
try {
|
2026-03-03 11:12:56 +08:00
|
|
|
|
const uploadRes = await new Promise((resolve, reject) => {
|
|
|
|
|
|
wx.uploadFile({
|
|
|
|
|
|
url: app.globalData.baseUrl + '/api/miniprogram/upload',
|
|
|
|
|
|
filePath: tempPath,
|
|
|
|
|
|
name: 'file',
|
|
|
|
|
|
formData: { folder: 'avatars' },
|
|
|
|
|
|
success: (r) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = JSON.parse(r.data)
|
|
|
|
|
|
data.success ? resolve(data) : reject(new Error(data.error || '上传失败'))
|
|
|
|
|
|
} catch (e) { reject(new Error('解析失败')) }
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (e) => reject(e)
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
const avatarUrl = app.globalData.baseUrl + uploadRes.data.url
|
|
|
|
|
|
const userInfo = this.data.userInfo
|
|
|
|
|
|
userInfo.avatar = avatarUrl
|
|
|
|
|
|
this.setData({ userInfo })
|
|
|
|
|
|
app.globalData.userInfo = userInfo
|
|
|
|
|
|
wx.setStorageSync('userInfo', userInfo)
|
|
|
|
|
|
await app.request('/api/miniprogram/user/update', { method: 'POST', data: { userId: userInfo.id, avatar: avatarUrl } })
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: '头像已更新', icon: 'success' })
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: e.message || '上传失败,请重试', icon: 'none' })
|
|
|
|
|
|
}
|
2026-02-24 14:35:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
2026-01-14 12:50:00 +08:00
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
goToVip() {
|
|
|
|
|
|
if (!this.data.isLoggedIn) { this.showLogin(); return }
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/vip/vip' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-28 15:16:23 +08:00
|
|
|
|
// 进入个人资料编辑页(stitch_soul)
|
|
|
|
|
|
goToProfileEdit() {
|
|
|
|
|
|
if (!this.data.isLoggedIn) { this.showLogin(); return }
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/profile-edit/profile-edit' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
async handleWithdraw() {
|
|
|
|
|
|
if (!this.data.isLoggedIn) { this.showLogin(); return }
|
|
|
|
|
|
const amount = parseFloat(this.data.pendingEarnings)
|
|
|
|
|
|
if (isNaN(amount) || amount <= 0) {
|
|
|
|
|
|
wx.showToast({ title: '暂无可提现金额', icon: 'none' })
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2026-02-28 15:16:23 +08:00
|
|
|
|
await this.ensureContactInfo(() => this.doWithdraw(amount))
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
async doWithdraw(amount) {
|
2026-01-14 12:50:00 +08:00
|
|
|
|
wx.showModal({
|
2026-02-24 14:35:58 +08:00
|
|
|
|
title: '申请提现',
|
|
|
|
|
|
content: `确认提现 ¥${amount.toFixed(2)} ?`,
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
if (!res.confirm) return
|
|
|
|
|
|
wx.showLoading({ title: '提交中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
const userId = app.globalData.userInfo?.id
|
2026-02-25 16:26:13 +08:00
|
|
|
|
await app.request({ url: '/api/miniprogram/withdraw', method: 'POST', data: { userId, amount } })
|
2026-02-24 14:35:58 +08:00
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: '提现申请已提交', icon: 'success' })
|
|
|
|
|
|
this.loadMyEarnings()
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
wx.showToast({ title: e.message || '提现失败', icon: 'none' })
|
2026-01-14 12:50:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-28 15:16:23 +08:00
|
|
|
|
// 提现/找伙伴前检查手机或微信号,未填则弹窗(stitch_soul)
|
|
|
|
|
|
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 || '',
|
|
|
|
|
|
pendingWithdraw: true,
|
|
|
|
|
|
})
|
|
|
|
|
|
this._contactCallback = callback
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
callback()
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
closeContactModal() {
|
|
|
|
|
|
this.setData({ showContactModal: false, pendingWithdraw: 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.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 })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-24 14:35:58 +08:00
|
|
|
|
// 阻止冒泡
|
2026-02-25 11:47:36 +08:00
|
|
|
|
stopPropagation() {},
|
|
|
|
|
|
|
|
|
|
|
|
onShareAppMessage() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Soul创业派对 - 我的',
|
|
|
|
|
|
path: ref ? `/pages/my/my?ref=${ref}` : '/pages/my/my'
|
|
|
|
|
|
}
|
2026-02-27 14:22:58 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShareTimeline() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
|
|
|
|
|
return { title: 'Soul创业派对 - 我的', query: ref ? `ref=${ref}` : '' }
|
2026-02-25 11:47:36 +08:00
|
|
|
|
}
|
2026-01-14 12:50:00 +08:00
|
|
|
|
})
|