ai-c/pages/profile/profile.js
2026-02-02 18:21:32 +08:00

641 lines
17 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const api = require('../../utils/api');
const util = require('../../utils/util');
const app = getApp();
Page({
data: {
defaultAvatar: '/images/default-avatar.svg',
me: {
id: '',
idShort: '',
nickname: '未登录',
avatar: '',
phone: ''
},
vip: {
levelText: '',
expireText: ''
},
balances: {
grass: 0,
commission: '0.00'
},
counts: {
orders: 0,
team: 0,
performance: 0
},
isLoggedIn: false,
isDistributor: false,
referralCode: '',
statusBarHeight: 20,
totalUnread: 0,
// Modal States
showPromoterModal: false,
showPromoterSuccess: false,
// 注册奖励
showRegistrationReward: false,
registrationRewardAmount: 0,
claiming: false,
auditStatus: 0,
// GF100 弹窗
showGf100Popup: false,
gf100ImageUrl: ''
},
onShow() {
this.setData({
statusBarHeight: wx.getSystemInfoSync().statusBarHeight,
auditStatus: app.globalData.auditStatus
});
wx.hideTabBar({ animation: false });
this.loadAll();
},
async loadAll() {
const isLoggedIn = app.globalData.isLoggedIn || !!wx.getStorageSync('auth_token');
this.setData({ isLoggedIn });
wx.showNavigationBarLoading();
try {
if (isLoggedIn) {
await Promise.all([
this.loadMe(),
this.loadBalance(),
this.loadCommission(),
this.loadCounts(),
this.loadUnreadCount()
]);
this.checkRegistrationReward();
this.checkGf100Popup();
} else {
this.setData({
me: { nickname: '未登录', avatar: this.data.defaultAvatar },
balances: { grass: 0, commission: '0.00' },
counts: { orders: 0, team: 0, performance: 0 },
totalUnread: 0
});
}
} catch (err) {
console.error('Load profile failed', err);
} finally {
wx.hideNavigationBarLoading();
}
},
/**
* 检查是否需要登录
* @returns {boolean} 是否已登录
*/
requireLogin() {
const isLoggedIn = app.globalData.isLoggedIn || !!wx.getStorageSync('auth_token');
if (!isLoggedIn) {
wx.showModal({
title: '提示',
content: '请先登录后再操作',
confirmText: '去登录',
success: (res) => {
if (res.confirm) {
wx.navigateTo({
url: '/pages/login/login'
});
}
}
});
return false;
}
return true;
},
async loadMe() {
try {
// Use direct request with cache busting to ensure fresh data
const res = await api.request('/auth/me', { data: { _t: Date.now() } });
// Correctly unwrap the data object from the response
const user = (res && res.data) ? res.data : {};
const id = user.id || '';
const idShort = id ? String(id).substring(0, 8).toUpperCase() : '';
const nickname = user.nickname || user.name || '微信用户';
// 处理头像:如果是默认头像则不处理,否则拼接完整路径
let avatar = user.avatar || user.avatar_url;
if (avatar) {
avatar = util.getFullImageUrl(avatar);
} else {
avatar = this.data.defaultAvatar;
}
const phone = user.phone || user.mobile || '';
// Determine Display Role
const distributorRole = user.distributorRole || user.role;
let roleText = '';
let roleClass = '';
const roleMap = {
'soulmate': { text: '心伴会员', class: 'vip-soulmate' },
'guardian': { text: '守护会员', class: 'vip-guardian' },
'companion': { text: '陪伴会员', class: 'vip-companion' },
'listener': { text: '倾听会员', class: 'vip-listener' },
'partner': { text: '城市合伙人', class: 'vip-partner' }
};
if (user.isDistributor && roleMap[distributorRole]) {
const info = roleMap[distributorRole];
roleText = info.text;
roleClass = info.class;
} else {
// Fallback to VIP
const vipLevel = Number(user.vip_level || 0);
if (vipLevel > 0) {
roleText = vipLevel >= 2 ? 'SVIP' : 'VIP';
roleClass = 'vip-normal';
}
}
this.setData({
me: { id, idShort, nickname, avatar, phone },
vip: { levelText: roleText || '', levelClass: roleClass },
isDistributor: !!user.isDistributor
});
// CRITICAL: Update global data and local storage to ensure avatar consistency across pages
if (app && app.setUserInfo) {
app.setUserInfo(user);
} else {
// Fallback if app.setUserInfo is not available
app.globalData.userInfo = user;
app.globalData.userId = user.id;
wx.setStorageSync('user_info', user);
}
} catch (e) {
console.error('loadMe error', e);
}
},
async loadBalance() {
try {
const res = await api.user.getBalance();
const data = (res && res.data) ? res.data : res;
const balance = data.flower_balance || data.balance || 0;
this.setData({
'balances.grass': Number(balance)
});
} catch (e) {
console.error('loadBalance error', e);
}
},
async loadCommission() {
try {
const res = await api.commission.getStats();
const data = (res && res.data) ? res.data : res;
const commission = data.commissionBalance || data.commission_balance || 0;
// Use individualPerformance for "Performance Data" card as per documentation
const performance = data.individualPerformance || data.individual_performance || data.totalContribution || data.total_contribution || 0;
this.setData({
'balances.commission': Number(commission).toFixed(2),
'counts.performance': this.formatAmount(performance)
});
} catch (e) {
console.error('loadCommission error', e);
}
},
/**
* 格式化金额超过一万显示为“x.x万”
* @param {number|string} val
*/
formatAmount(val) {
const num = Number(val || 0);
if (num >= 10000) {
return (num / 10000).toFixed(1) + '万';
}
return num.toFixed(2);
},
async loadCounts() {
try {
// 1. Fetch self orders (all statuses)
const selfOrdersRes = await api.payment.getOrders({ page: 1, pageSize: 1 });
const selfCount = (selfOrdersRes.data && selfOrdersRes.data.total) ? selfOrdersRes.data.total : 0;
// 2. Fetch promotion orders (records) - usually pageSize=1 is enough to get total
// Note: check backend response structure for total count
const promoRes = await api.commission.getRecords({ page: 1, pageSize: 1 });
const promoCount = (promoRes.data && promoRes.data.total) ? promoRes.data.total : 0;
// 3. Fetch team members count
const teamRes = await api.commission.getReferrals({ page: 1, pageSize: 1 });
const teamCount = (teamRes.data && teamRes.data.total) ? teamRes.data.total : 0;
this.setData({
'counts.orders': selfCount + promoCount,
'counts.team': teamCount
});
} catch (err) {
console.error('loadCounts failed', err);
// Keep existing data or set to 0 on error
// this.setData({ 'counts.orders': 0, 'counts.team': 0 });
}
},
async loadUnreadCount() {
if (!this.data.isLoggedIn) {
this.setData({ totalUnread: 0 });
return;
}
try {
const [convRes, proactiveRes] = await Promise.all([
api.chat.getConversations(),
api.proactiveMessage.getPending ? api.proactiveMessage.getPending() : Promise.resolve({ success: true, data: [] })
]);
let totalUnread = 0;
if (convRes.success && convRes.data) {
totalUnread = convRes.data.reduce((sum, conv) => sum + (conv.unread_count || 0), 0);
}
if (proactiveRes.success && proactiveRes.data && Array.isArray(proactiveRes.data)) {
totalUnread += proactiveRes.data.length;
}
this.setData({ totalUnread });
} catch (err) {
console.log('获取未读消息数失败', err);
this.setData({ totalUnread: 0 });
}
},
goSettings() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/settings/settings' });
}
},
goEdit() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/edit-profile/edit-profile' });
}
},
goRecharge() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/recharge/recharge' });
}
},
goOrders() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/orders/orders' });
}
},
goTeam() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/team/team' });
}
},
goGiftShop() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/gift-shop/gift-shop' });
}
},
goBackpack() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/backpack/backpack' });
}
},
goMyActivities() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/my-activities/my-activities' });
}
},
goWithdraw() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/withdraw/withdraw' });
}
},
goCommission() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/commission/commission' });
}
},
goPerformance() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/performance/performance' });
}
},
goCooperation() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/subpackages/cooperation/pages/cooperation/cooperation' });
}
},
goSupport() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/support/support' });
}
},
goPromote() {
if (this.requireLogin()) {
wx.navigateTo({ url: '/pages/promote/promote' });
}
},
onAvatarError() {
this.setData({
'me.avatar': this.data.defaultAvatar
});
},
async handleLogout() {
wx.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: async (res) => {
if (res.confirm) {
try {
await api.auth.logout();
} catch (e) {
console.error('logout api error', e);
}
wx.removeStorageSync('auth_token');
wx.removeStorageSync('user_info');
app.globalData.isLoggedIn = false;
app.globalData.userInfo = null;
this.loadAll();
wx.showToast({
title: '已退出登录',
icon: 'success'
});
}
}
});
},
/**
* 检查注册奖励领取资格
*/
async checkRegistrationReward() {
try {
if (!api.lovePoints || typeof api.lovePoints.checkRegistrationReward !== 'function') {
return;
}
// 检查注册奖励领取资格 - 增加静默处理,避免 404 时控制台报错
const res = await api.lovePoints.checkRegistrationReward();
if (res && res.success && res.data && res.data.eligible) {
this.setData({
showRegistrationReward: true,
registrationRewardAmount: res.data.amount || 100
});
}
} catch (err) {
// 生产环境可能未部署此接口,静默处理
if (err.code !== 404) {
console.warn('[profile] 检查注册奖励静默失败:', err.message || '接口可能未部署');
}
}
},
/**
* 领取注册奖励
*/
async onClaimReward() {
if (this.data.claiming) return;
if (!api.lovePoints || typeof api.lovePoints.claimRegistrationReward !== 'function') {
wx.showToast({ title: '功能暂不可用', icon: 'none' });
return;
}
this.setData({ claiming: true });
wx.showLoading({ title: '领取中...' });
try {
const res = await api.lovePoints.claimRegistrationReward();
wx.hideLoading();
if (res.success) {
wx.showToast({
title: '领取成功',
icon: 'success',
duration: 2000
});
this.setData({
showRegistrationReward: false
});
// 如果后端返回了免费畅聊时间,可以做提示
if (res.data && res.data.free_chat_time) {
console.log('[profile] 获得免费畅聊时间:', res.data.free_chat_time);
setTimeout(() => {
wx.showModal({
title: '额外奖励',
content: '恭喜获得 60 分钟免费畅聊时间,现在就去和 AI 角色聊天吧!',
confirmText: '去聊天',
success: (modalRes) => {
if (modalRes.confirm) {
wx.switchTab({ url: '/pages/index/index' });
}
}
});
}, 2000);
}
// 刷新余额
this.loadBalance();
} else {
wx.showToast({
title: res.message || '领取失败',
icon: 'none'
});
}
} catch (err) {
wx.hideLoading();
console.error('[profile] 领取注册奖励失败:', err);
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
});
} finally {
this.setData({ claiming: false });
}
},
/**
* 关闭注册奖励弹窗
*/
closeRewardPopup() {
this.setData({
showRegistrationReward: false
});
},
/**
* 检查 GF100 弹窗状态
*/
async checkGf100Popup() {
if (!this.data.isLoggedIn) return;
try {
const res = await api.lovePoints.checkGf100Status();
console.log('[profile] GF100 检查结果:', res);
if (res.success && res.data && res.data.showPopup) {
const imageUrl = res.data.imageUrl;
this.setData({
showGf100Popup: true,
gf100ImageUrl: imageUrl ? util.getFullImageUrl(imageUrl) : '/images/gf100.png'
});
}
} catch (err) {
console.error('[profile] 检查 GF100 弹窗失败:', err);
}
},
/**
* 领取 GF100 奖励
*/
async onClaimGf100() {
if (this.data.claiming) return;
this.setData({ claiming: true });
wx.showLoading({ title: '领取中...', mask: true });
try {
const res = await api.lovePoints.claimGf100();
wx.hideLoading();
if (res.success) {
wx.showToast({
title: '领取成功',
icon: 'success',
duration: 2000
});
this.setData({
showGf100Popup: false
});
// 弹出获得 60 分钟免费畅聊的提示
setTimeout(() => {
wx.showModal({
title: '领取成功',
content: '恭喜获得 100 爱心 + 60 分钟免费畅聊时间!',
confirmText: '去聊天',
success: (modalRes) => {
if (modalRes.confirm) {
wx.switchTab({ url: '/pages/chat/chat' })
}
}
});
}, 500);
// 刷新余额
this.loadBalance();
} else {
wx.showToast({
title: res.message || '领取失败',
icon: 'none'
});
}
} catch (err) {
wx.hideLoading();
console.error('[profile] 领取 GF100 失败:', err);
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
});
} finally {
this.setData({ claiming: false });
}
},
/**
* 关闭 GF100 弹窗
*/
closeGf100Popup() {
this.setData({
showGf100Popup: false
});
},
preventBubble() { },
preventTouchMove() { },
async onLoad() {
await this.loadReferralCode()
},
async loadReferralCode() {
if (!this.data.isLoggedIn) return
try {
const res = await api.commission.getStats()
if (res.success && res.data) {
this.setData({ referralCode: res.data.referralCode || '' })
}
} catch (err) {
console.error('加载推荐码失败:', err)
}
},
onShareAppMessage() {
const { referralCode, isDistributor } = this.data
const referralCodeParam = referralCode ? `?referralCode=${referralCode}` : ''
this.recordShareReward()
return {
title: isDistributor ? `我的推荐码:${referralCode},注册即可享受优惠!` : '欢迎来到心伴俱乐部 - 随时可聊 一直陪伴',
path: `/pages/index/index${referralCodeParam}`,
imageUrl: isDistributor ? '/images/share-commission.png' : '/images/icon-heart-new.png'
}
},
onShareTimeline() {
const { referralCode, isDistributor } = this.data
const query = referralCode ? `referralCode=${referralCode}` : ''
this.recordShareReward()
return {
title: isDistributor ? `推荐码:${referralCode},注册即可享受优惠!` : '心伴俱乐部 - 随时可聊 一直陪伴',
query: query,
imageUrl: isDistributor ? '/images/share-commission.png' : '/images/icon-heart-new.png'
}
},
/**
* 静默记录分享奖励分享人A获得+100爱心值
*/
async recordShareReward() {
try {
const res = await api.lovePoints.share()
console.log('[profile] 分享爱心值奖励:', res)
} catch (err) {
console.error('[profile] 记录分享奖励失败:', err)
}
},
// Tab Bar Switching
switchTab(e) {
const path = e.currentTarget.dataset.path;
const app = getApp();
if (path === '/pages/chat/chat') {
if (!app.globalData.isLoggedIn && !wx.getStorageSync('auth_token')) {
wx.navigateTo({
url: '/pages/login/login?redirect=' + encodeURIComponent(path)
});
return;
}
}
wx.switchTab({ url: path });
}
});