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

663 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 auth = require('../../utils/auth')
const config = require('../../config/index')
Page({
data: {
invitationCode: '',
referralCode: '', // 推荐码(佣金系统)
shareUrl: '',
stats: {
total_invites: 0,
completed_invites: 0
},
// 佣金统计
commissionStats: {
totalReferrals: 0,
commissionBalance: 0,
totalEarned: 0
},
lovePoints: 0,
shareCount: 0,
maxShareCount: 3,
loading: false,
isDistributor: false, // 是否是分销商
// 海报相关
posterTemplates: [],
currentPosterIndex: 0,
generatingPoster: false,
shareConfig: null
},
async onLoad() {
// 统一登录验证
const isValid = await auth.ensureLogin({
pageName: 'invite',
redirectUrl: '/pages/invite/invite'
})
if (!isValid) return
// 验证通过后稍作延迟确保token稳定
await new Promise(resolve => setTimeout(resolve, 50))
// 加载数据
this.loadData()
},
onShow() {
// 每次显示页面时刷新数据(已登录的情况下)
const app = getApp()
if (app.globalData.isLoggedIn) {
this.loadData()
}
},
/**
* 加载所有数据
*/
async loadData() {
if (this.data.loading) return
this.setData({ loading: true })
try {
await Promise.all([
this.loadInvitationCode(),
this.loadCommissionStats(), // 加载佣金统计
this.getLovePoints(),
this.getTodayShareCount(),
this.loadPosterTemplates(),
this.loadShareConfig()
])
} catch (error) {
console.error('加载数据失败:', error)
} finally {
this.setData({ loading: false })
}
},
/**
* 获取邀请码
*/
async loadInvitationCode() {
try {
const res = await api.lovePoints.getInvitationCode()
if (res.success) {
this.setData({
invitationCode: res.data.invitation_code,
shareUrl: res.data.share_url,
stats: res.data.stats
})
}
} catch (error) {
console.error('获取邀请码失败:', error)
// 401错误由API层统一处理这里只处理其他错误
if (error.code !== 401) {
wx.showToast({
title: error.message || '获取邀请码失败',
icon: 'none'
})
}
}
},
/**
* 加载佣金统计数据
*/
async loadCommissionStats() {
try {
const res = await api.commission.getStats()
if (res.success && res.data) {
this.setData({
referralCode: res.data.referralCode || '',
isDistributor: res.data.isDistributor || false,
commissionStats: {
totalReferrals: res.data.totalReferrals || 0,
commissionBalance: res.data.commissionBalance || 0,
totalEarned: res.data.totalEarned || 0
}
})
}
} catch (error) {
console.error('获取佣金统计失败:', error)
// 不显示错误提示,静默失败
}
},
/**
* 获取爱心值余额(使用后端新接口)
*/
getLovePoints() {
return new Promise((resolve, reject) => {
const token = wx.getStorageSync('auth_token')
if (!token) {
resolve()
return
}
wx.request({
url: `${config.API_BASE_URL}/love-points/balance`,
method: 'GET',
header: {
'Authorization': `Bearer ${token}`
},
success: (res) => {
console.log('爱心值余额API响应:', res.data)
if (res.data.success) {
this.setData({
lovePoints: res.data.data.love_points
})
resolve(res.data.data)
} else {
reject(new Error(res.data.error))
}
},
fail: reject
})
})
},
/**
* 获取今日分享次数(使用后端新接口)
*/
getTodayShareCount() {
return new Promise((resolve, reject) => {
const token = wx.getStorageSync('auth_token')
if (!token) {
resolve()
return
}
wx.request({
url: `${config.API_BASE_URL}/love-points/share-count`,
method: 'GET',
header: {
'Authorization': `Bearer ${token}`
},
success: (res) => {
console.log('分享次数API响应:', res.data)
if (res.data.success) {
this.setData({
shareCount: res.data.data.count,
maxShareCount: res.data.data.max
})
resolve(res.data.data)
} else {
reject(new Error(res.data.error))
}
},
fail: reject
})
})
},
/**
* 复制邀请码
*/
copyInviteCode() {
const { isDistributor, referralCode, invitationCode } = this.data;
// 如果是分销商且有推荐码,优先复制推荐码
const codeToCopy = (isDistributor && referralCode) ? referralCode : invitationCode;
if (!codeToCopy) {
wx.showToast({
title: '邀请码加载中...',
icon: 'none'
})
return
}
wx.setClipboardData({
data: codeToCopy,
success: () => {
wx.showToast({
title: '邀请码已复制',
icon: 'success'
})
}
})
},
/**
* 查看佣金中心
*/
goToCommission() {
wx.navigateTo({
url: '/pages/commission/commission'
})
},
/**
* 点击分享按钮
*/
onShareTap() {
console.log('用户点击了分享按钮')
// 检查登录状态
const token = wx.getStorageSync('auth_token')
if (!token) {
wx.showModal({
title: '提示',
content: '请先登录',
confirmText: '去登录',
success: (res) => {
if (res.confirm) {
wx.navigateTo({
url: '/pages/login/login'
})
}
}
})
return
}
// 检查是否达到上限
if (this.data.shareCount >= this.data.maxShareCount) {
wx.showToast({
title: '今日分享次数已达上限',
icon: 'none',
duration: 2000
})
return
}
// 立即记录分享
this.recordShare()
},
/**
* 记录分享并获得爱心值(使用后端新接口)
*/
recordShare() {
const token = wx.getStorageSync('auth_token')
if (!token) return
wx.showLoading({
title: '处理中...',
mask: true
})
wx.request({
url: `${config.API_BASE_URL}/love-points/share`,
method: 'POST',
header: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
success: (res) => {
wx.hideLoading()
console.log('分享奖励API响应:', res.data)
if (res.data.success) {
const newShareCount = this.data.shareCount + 1
const newLovePoints = this.data.lovePoints + res.data.data.earned
this.setData({
shareCount: newShareCount,
lovePoints: newLovePoints
})
wx.showToast({
title: `+${res.data.data.earned} 爱心值`,
icon: 'success',
duration: 2000
})
const app = getApp()
if (app.globalData) {
app.globalData.lovePoints = newLovePoints
}
this.triggerPageRefresh()
} else {
wx.showToast({
title: res.data.error || '分享失败',
icon: 'none',
duration: 2000
})
}
},
fail: (error) => {
wx.hideLoading()
console.error('分享奖励API调用失败:', error)
wx.showToast({
title: '网络错误,请稍后重试',
icon: 'none',
duration: 2000
})
}
})
},
/**
* 静默记录分享奖励(用于 onShareAppMessage/onShareTimeline
* 不显示 loading 和 Toast后台静默调用
* 分享人A获得+100爱心值
*/
async recordShareReward() {
try {
const token = wx.getStorageSync('auth_token')
if (!token) return
const res = await new Promise((resolve, reject) => {
wx.request({
url: `${config.API_BASE_URL}/love-points/share`,
method: 'POST',
header: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
success: resolve,
fail: reject
})
})
if (res.data && res.data.success && res.data.data) {
const newShareCount = this.data.shareCount + 1
const newLovePoints = this.data.lovePoints + (res.data.data.earned || 0)
this.setData({
shareCount: newShareCount,
lovePoints: newLovePoints
})
console.log('[invite] 分享爱心值奖励:', res.data.data.earned)
}
} catch (err) {
console.error('[invite] 记录分享奖励失败:', err)
}
},
/**
* 触发其他页面刷新
*/
triggerPageRefresh() {
const pages = getCurrentPages()
if (pages.length > 1) {
const prevPage = pages[pages.length - 2]
// 如果上一个页面有刷新方法,调用它
if (prevPage.onLovePointsUpdate) {
prevPage.onLovePointsUpdate()
}
if (prevPage.loadData) {
prevPage.loadData()
}
}
},
/**
* 微信分享配置
* 用户点击分享按钮时触发,返回分享信息
* 同时记录爱心值奖励分享人A获得+100
*/
onShareAppMessage() {
const userId = wx.getStorageSync('user_id') || ''
const { referralCode, isDistributor, shareConfig } = this.data
const inviterParam = userId ? `?inviter=${userId}` : ''
const referralParam = referralCode ? `?referralCode=${referralCode}` : ''
// 记录爱心值奖励分享人A获得+100
this.recordShareReward()
if (shareConfig && (userId || (isDistributor && referralCode))) {
return {
title: shareConfig.title,
desc: shareConfig.desc || '',
path: `${shareConfig.path || '/pages/index/index'}${isDistributor && referralCode ? referralParam : inviterParam}`,
imageUrl: shareConfig.imageUrl
}
}
if (isDistributor && referralCode) {
return {
title: `我的推荐码:${referralCode},注册即可享受优惠!`,
path: `/pages/index/index?referralCode=${referralCode}`,
imageUrl: shareConfig?.imageUrl || '/images/share-cover.jpg'
}
}
if (userId) {
return {
title: '邀请你一起来玩AI陪伴超多有趣角色等你来聊~',
path: `/pages/index/index?inviter=${userId}`,
imageUrl: shareConfig?.imageUrl || '/images/share-cover.jpg'
}
}
return {
title: 'AI情感陪伴随时可聊 一直陪伴',
path: '/pages/index/index',
imageUrl: shareConfig?.imageUrl || '/images/share-cover.jpg'
}
},
/**
* 分享到朋友圈
*/
onShareTimeline() {
const { referralCode, isDistributor, shareConfig } = this.data
const userId = wx.getStorageSync('user_id') || ''
this.recordShareReward()
if (shareConfig && (userId || (isDistributor && referralCode))) {
return {
title: shareConfig.title,
query: isDistributor && referralCode ? `referralCode=${referralCode}` : (userId ? `inviter=${userId}` : ''),
imageUrl: shareConfig.imageUrl
}
}
if (isDistributor && referralCode) {
return {
title: `推荐码:${referralCode},注册即可享受优惠!`,
query: `referralCode=${referralCode}`,
imageUrl: shareConfig?.imageUrl || '/images/share-cover.jpg'
}
}
if (userId) {
return {
title: '邀请你一起来玩AI陪伴~',
query: `inviter=${userId}`,
imageUrl: shareConfig?.imageUrl || '/images/share-cover.jpg'
}
}
return {
title: 'AI情感陪伴',
query: '',
imageUrl: shareConfig?.imageUrl || '/images/share-cover.jpg'
}
},
/**
* 加载海报模板
* 调用后端API获取海报图片
*/
async loadPosterTemplates() {
try {
const res = await api.pageAssets.getAssets('poster_templates')
if (res.success && res.data && res.data.length > 0) {
const posterTemplates = res.data.map(item => ({
id: item.id,
imageUrl: this.processImageUrl(item.asset_url || item.imageUrl || item.url)
}))
this.setData({
posterTemplates,
currentPosterIndex: 0
})
console.log(`加载了 ${posterTemplates.length} 个海报模板`)
} else {
this.setDefaultPosterTemplates()
}
} catch (error) {
console.error('加载海报模板失败:', error)
this.setDefaultPosterTemplates()
}
},
/**
* 设置默认海报模板(降级方案 - 使用CDN URL
*/
setDefaultPosterTemplates() {
const cdnBase = 'https://ai-c.maimanji.com/images'
this.setData({
posterTemplates: [
{ id: 1, imageUrl: `${cdnBase}/service-banner-1.png` },
{ id: 2, imageUrl: `${cdnBase}/service-banner-2.png` }
],
currentPosterIndex: 0
})
console.log('使用默认海报模板配置')
},
/**
* 加载分享配置
*/
async loadShareConfig() {
try {
const res = await api.promotion.getShareConfig('invite')
if (res.success && res.data) {
const util = require('../../utils/util')
const shareConfig = {
...res.data,
imageUrl: res.data.imageUrl ? util.getFullImageUrl(res.data.imageUrl) : ''
}
this.setData({ shareConfig })
}
} catch (error) {
console.error('加载分享配置失败', error)
}
},
/**
* 切换海报
*/
onPosterChange(e) {
this.setData({
currentPosterIndex: e.detail.current
})
},
/**
* 生成并保存海报
*/
async generatePoster() {
if (this.data.generatingPoster) return
this.setData({ generatingPoster: true })
wx.showLoading({ title: '生成中...' })
try {
const template = this.data.posterTemplates[this.data.currentPosterIndex]
const userInfo = wx.getStorageSync('user_info') || {}
const nickname = userInfo.nickname || '神秘用户'
const query = wx.createSelectorQuery()
query.select('#posterCanvas')
.fields({ node: true, size: true })
.exec(async (res) => {
if (!res[0]) {
throw new Error('Canvas not found')
}
const canvas = res[0].node
const ctx = canvas.getContext('2d')
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
const width = 300
const height = 533
// 绘制背景
const bgImage = canvas.createImage()
bgImage.src = template.imageUrl
await new Promise((resolve) => {
bgImage.onload = resolve
bgImage.onerror = (e) => { console.error('BG Error', e); resolve() }
})
ctx.drawImage(bgImage, 0, 0, width, height)
// 绘制二维码背景
ctx.fillStyle = '#FFFFFF'
ctx.fillRect(20, height - 120, 100, 100)
// 模拟二维码
ctx.fillStyle = '#000000'
ctx.fillRect(25, height - 115, 90, 90)
// 绘制文字
ctx.fillStyle = '#FFFFFF'
ctx.font = 'bold 18px sans-serif'
ctx.fillText(nickname, 130, height - 80)
ctx.font = '14px sans-serif'
ctx.fillText('邀请你体验AI心伴', 130, height - 55)
wx.canvasToTempFilePath({
canvas,
success: (fileRes) => {
wx.saveImageToPhotosAlbum({
filePath: fileRes.tempFilePath,
success: () => {
wx.hideLoading()
wx.showToast({ title: '已保存到相册', icon: 'success' })
this.setData({ generatingPoster: false })
},
fail: (err) => {
console.error('保存失败', err)
wx.hideLoading()
if (err.errMsg.includes('auth')) {
wx.showModal({
title: '提示',
content: '需要保存图片到相册的权限,是否去设置?',
success: (mRes) => {
if (mRes.confirm) wx.openSetting()
}
})
} else {
wx.showToast({ title: '保存失败', icon: 'none' })
}
this.setData({ generatingPoster: false })
}
})
},
fail: (err) => {
console.error('导出图片失败', err)
wx.hideLoading()
this.setData({ generatingPoster: false })
}
})
})
} catch (error) {
console.error('流程错误:', error)
wx.hideLoading()
this.setData({ generatingPoster: false })
}
},
/**
* 查看爱心值明细
*/
viewTransactions() {
wx.navigateTo({
url: '/pages/love-transactions/love-transactions'
})
},
/**
* 下拉刷新
*/
onPullDownRefresh() {
this.loadData().then(() => {
wx.stopPullDownRefresh()
})
}
})