🎉 v1.3.1: 完美版本 - H5和小程序100%统一,64章精准数据,寻找合作伙伴功能

This commit is contained in:
卡若
2026-01-14 12:50:00 +08:00
parent 326c9e6905
commit 5420499117
87 changed files with 18849 additions and 248 deletions

452
miniprogram/pages/my/my.js Normal file
View File

@@ -0,0 +1,452 @@
// pages/my/my.js
const app = getApp()
Page({
data: {
userInfo: {},
userStats: {
readChapters: 0,
readMinutes: 0,
bookmarks: 0
},
earnings: {
total: '0.00',
available: '0.00',
withdrawn: '0.00'
},
referralData: {
totalUsers: 0,
totalOrders: 0,
commissionRate: 90
},
menuBadges: {
orders: 0
},
showPoster: false
},
onLoad(options) {
// 检查是否有tab参数
if (options.tab === 'referral') {
// 自动展开分销中心
this.setData({ expandReferral: true })
}
},
onShow() {
this.loadUserInfo()
this.loadUserStats()
this.loadEarnings()
this.loadReferralData()
},
// 加载用户信息
loadUserInfo() {
const userInfo = app.getUserInfo()
if (userInfo) {
this.setData({ userInfo })
} else {
// 未登录状态
this.setData({
userInfo: {
avatar: '',
nickname: '点击登录',
id: '',
inviteCode: ''
}
})
}
},
// 加载用户统计
loadUserStats() {
const token = wx.getStorageSync('token')
if (!token) return
wx.request({
url: `${app.globalData.apiBase}/user/stats`,
header: {
'Authorization': `Bearer ${token}`
},
success: (res) => {
if (res.statusCode === 200) {
this.setData({
userStats: res.data.stats
})
}
},
fail: () => {
// 使用缓存数据
const cached = wx.getStorageSync('userStats')
if (cached) {
this.setData({ userStats: cached })
}
}
})
},
// 加载收益数据
loadEarnings() {
const token = wx.getStorageSync('token')
if (!token) return
wx.request({
url: `${app.globalData.apiBase}/referral/earnings`,
header: {
'Authorization': `Bearer ${token}`
},
success: (res) => {
if (res.statusCode === 200) {
this.setData({
earnings: {
total: res.data.total || '0.00',
available: res.data.available || '0.00',
withdrawn: res.data.withdrawn || '0.00'
}
})
}
}
})
},
// 加载推广数据
loadReferralData() {
const token = wx.getStorageSync('token')
if (!token) return
wx.request({
url: `${app.globalData.apiBase}/referral/stats`,
header: {
'Authorization': `Bearer ${token}`
},
success: (res) => {
if (res.statusCode === 200) {
this.setData({
referralData: res.data
})
}
}
})
},
// 编辑资料
editProfile() {
const userInfo = this.data.userInfo
if (!userInfo.id) {
// 未登录,执行登录
this.doLogin()
return
}
wx.navigateTo({
url: '/pages/profile/edit'
})
},
// 执行登录
doLogin() {
wx.showLoading({ title: '登录中...', mask: true })
app.wxLogin((success, user) => {
wx.hideLoading()
if (success) {
wx.showToast({
title: '登录成功',
icon: 'success'
})
this.setData({ userInfo: user })
this.loadUserStats()
this.loadEarnings()
this.loadReferralData()
} else {
wx.showToast({
title: '登录失败',
icon: 'none'
})
}
})
},
// 生成推广海报
generatePoster() {
const userInfo = this.data.userInfo
if (!userInfo.id) {
this.showLoginModal()
return
}
this.setData({ showPoster: true })
wx.showLoading({ title: '生成中...', mask: true })
// 使用Canvas绘制海报
setTimeout(() => {
this.drawPoster()
wx.hideLoading()
}, 500)
},
// 绘制海报
drawPoster() {
const ctx = wx.createCanvasContext('posterCanvas')
const userInfo = this.data.userInfo
// 背景
ctx.setFillStyle('#000000')
ctx.fillRect(0, 0, 375, 500)
// 渐变背景
const gradient = ctx.createLinearGradient(0, 0, 0, 500)
gradient.addColorStop(0, 'rgba(255, 77, 79, 0.3)')
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)')
ctx.setFillStyle(gradient)
ctx.fillRect(0, 0, 375, 500)
// 标题
ctx.setFontSize(32)
ctx.setFillStyle('#FFFFFF')
ctx.setTextAlign('center')
ctx.fillText('Soul派对·创业实验', 187.5, 60)
// 邀请码
ctx.setFontSize(48)
ctx.setFillStyle('#FF4D4F')
ctx.fillText(userInfo.inviteCode || 'XXXXXX', 187.5, 250)
// 提示文字
ctx.setFontSize(24)
ctx.setFillStyle('rgba(255, 255, 255, 0.8)')
ctx.fillText('使用此邀请码购买,双方都有佣金!', 187.5, 320)
// 二维码占位
ctx.setStrokeStyle('#FFFFFF')
ctx.strokeRect(137.5, 360, 100, 100)
ctx.setFontSize(16)
ctx.setFillStyle('rgba(255, 255, 255, 0.5)')
ctx.fillText('扫码阅读', 187.5, 420)
ctx.draw()
},
// 关闭海报
closePoster() {
this.setData({ showPoster: false })
},
// 阻止冒泡
stopPropagation() {},
// 保存海报
savePoster() {
wx.canvasToTempFilePath({
canvasId: 'posterCanvas',
success: (res) => {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
wx.showToast({
title: '保存成功',
icon: 'success'
})
this.closePoster()
},
fail: () => {
wx.showToast({
title: '保存失败',
icon: 'none'
})
}
})
}
})
},
// 提现
withdraw() {
const earnings = this.data.earnings
const available = parseFloat(earnings.available)
if (available < 1) {
wx.showToast({
title: '可提现金额不足1元',
icon: 'none'
})
return
}
wx.navigateTo({
url: `/pages/withdraw/withdraw?amount=${available}`
})
},
// 复制邀请码
copyInviteCode() {
const inviteCode = this.data.userInfo.inviteCode
if (!inviteCode) {
wx.showToast({
title: '请先登录',
icon: 'none'
})
return
}
wx.setClipboardData({
data: inviteCode,
success: () => {
wx.showToast({
title: '已复制邀请码',
icon: 'success'
})
}
})
},
// 查看推荐列表
viewReferrals() {
wx.navigateTo({
url: '/pages/referral/list'
})
},
// 查看订单列表
viewOrders() {
wx.navigateTo({
url: '/pages/referral/orders'
})
},
// 查看佣金明细
viewCommission() {
wx.navigateTo({
url: '/pages/referral/commission'
})
},
// 我的订单
goToOrders() {
wx.navigateTo({
url: '/pages/orders/list'
})
},
// 阅读历史
goToReadHistory() {
wx.navigateTo({
url: '/pages/history/read'
})
},
// 阅读时长
goToReadTime() {
wx.showToast({
title: '功能开发中',
icon: 'none'
})
},
// 书签
goToBookmarks() {
wx.navigateTo({
url: '/pages/bookmarks/list'
})
},
// 阅读笔记
goToNotes() {
wx.navigateTo({
url: '/pages/notes/list'
})
},
// 设置
goToSettings() {
wx.navigateTo({
url: '/pages/settings/index'
})
},
// 联系客服
contactSupport() {
wx.showToast({
title: '客服功能开发中',
icon: 'none'
})
},
// 关于我们
about() {
wx.navigateTo({
url: '/pages/about/index'
})
},
// 退出登录
logout() {
wx.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
wx.removeStorageSync('token')
wx.removeStorageSync('userInfo')
app.globalData.userInfo = null
this.setData({
userInfo: {
avatar: '',
nickname: '点击登录',
id: '',
inviteCode: ''
},
earnings: {
total: '0.00',
available: '0.00',
withdrawn: '0.00'
},
referralData: {
totalUsers: 0,
totalOrders: 0,
commissionRate: 90
}
})
wx.showToast({
title: '已退出登录',
icon: 'success'
})
}
}
})
},
// 显示登录弹窗
showLoginModal() {
wx.showModal({
title: '需要登录',
content: '请先登录账号',
confirmText: '立即登录',
success: (res) => {
if (res.confirm) {
this.doLogin()
}
}
})
},
// 下拉刷新
onPullDownRefresh() {
this.loadUserInfo()
this.loadUserStats()
this.loadEarnings()
this.loadReferralData()
setTimeout(() => {
wx.stopPullDownRefresh()
}, 1000)
}
})

View File

@@ -0,0 +1,204 @@
<!--pages/my/my.wxml-->
<view class="container my-container page-transition">
<!-- 用户信息卡片 -->
<view class="user-card glass-effect">
<view class="user-header">
<image
class="user-avatar"
src="{{userInfo.avatar || '/assets/images/default-avatar.png'}}"
mode="aspectFill"
bindtap="editProfile"
></image>
<view class="user-info">
<view class="user-name">{{userInfo.nickname || '点击登录'}}</view>
<view class="user-id">ID: {{userInfo.id || '---'}}</view>
</view>
<view class="vip-badge" wx:if="{{userInfo.isPurchased}}">
<text class="vip-text">已购</text>
</view>
</view>
<!-- 阅读统计 -->
<view class="user-stats">
<view class="stat-item" bindtap="goToReadHistory">
<view class="stat-value">{{userStats.readChapters}}</view>
<view class="stat-label">已读章节</view>
</view>
<view class="stat-divider"></view>
<view class="stat-item" bindtap="goToReadTime">
<view class="stat-value">{{userStats.readMinutes}}</view>
<view class="stat-label">阅读时长(分)</view>
</view>
<view class="stat-divider"></view>
<view class="stat-item" bindtap="goToBookmarks">
<view class="stat-value">{{userStats.bookmarks}}</view>
<view class="stat-label">书签</view>
</view>
</view>
</view>
<!-- 分销中心(重点功能) -->
<view class="referral-section card">
<view class="section-header">
<view class="section-title">
<text class="title-icon">💰</text>
<text class="title-text">分销中心</text>
</view>
<view class="referral-status">
<text class="status-text">佣金比例:</text>
<text class="status-value">90%</text>
</view>
</view>
<!-- 收益概览 -->
<view class="earnings-overview">
<view class="earnings-main">
<view class="earnings-label">累计收益</view>
<view class="earnings-amount">¥{{earnings.total}}</view>
</view>
<view class="earnings-sub">
<view class="sub-item">
<text class="sub-label">可提现</text>
<text class="sub-value brand-color">¥{{earnings.available}}</text>
</view>
<view class="sub-item">
<text class="sub-label">已提现</text>
<text class="sub-value">¥{{earnings.withdrawn}}</text>
</view>
</view>
</view>
<!-- 快速操作 -->
<view class="referral-actions">
<button class="btn-primary action-btn" bindtap="generatePoster">
生成推广海报
</button>
<button class="btn-secondary action-btn" bindtap="withdraw">
立即提现
</button>
</view>
<!-- 推广数据 -->
<view class="referral-stats">
<view class="referral-stat-item" bindtap="viewReferrals">
<view class="stat-number">{{referralData.totalUsers}}</view>
<view class="stat-name">推荐人数</view>
</view>
<view class="referral-stat-item" bindtap="viewOrders">
<view class="stat-number">{{referralData.totalOrders}}</view>
<view class="stat-name">成交订单</view>
</view>
<view class="referral-stat-item" bindtap="viewCommission">
<view class="stat-number">{{referralData.commissionRate}}%</view>
<view class="stat-name">佣金率</view>
</view>
</view>
<!-- 我的邀请码 -->
<view class="invite-code-section">
<view class="invite-label">我的邀请码</view>
<view class="invite-code-box">
<text class="invite-code">{{userInfo.inviteCode || '---'}}</text>
<button class="copy-btn" bindtap="copyInviteCode">复制</button>
</view>
</view>
</view>
<!-- 功能菜单 -->
<view class="menu-section">
<view class="menu-group card">
<view class="menu-item" bindtap="goToOrders">
<view class="menu-left">
<text class="menu-icon">📦</text>
<text class="menu-text">我的订单</text>
</view>
<view class="menu-right">
<text class="menu-badge" wx:if="{{menuBadges.orders > 0}}">{{menuBadges.orders}}</text>
<text class="menu-arrow">></text>
</view>
</view>
<view class="menu-divider"></view>
<view class="menu-item" bindtap="goToBookmarks">
<view class="menu-left">
<text class="menu-icon">🔖</text>
<text class="menu-text">我的书签</text>
</view>
<view class="menu-right">
<text class="menu-arrow">></text>
</view>
</view>
<view class="menu-divider"></view>
<view class="menu-item" bindtap="goToNotes">
<view class="menu-left">
<text class="menu-icon">📝</text>
<text class="menu-text">阅读笔记</text>
</view>
<view class="menu-right">
<text class="menu-arrow">></text>
</view>
</view>
</view>
<view class="menu-group card">
<view class="menu-item" bindtap="goToSettings">
<view class="menu-left">
<text class="menu-icon">⚙️</text>
<text class="menu-text">设置</text>
</view>
<view class="menu-right">
<text class="menu-arrow">></text>
</view>
</view>
<view class="menu-divider"></view>
<view class="menu-item" bindtap="contactSupport">
<view class="menu-left">
<text class="menu-icon">💬</text>
<text class="menu-text">联系客服</text>
</view>
<view class="menu-right">
<text class="menu-arrow">></text>
</view>
</view>
<view class="menu-divider"></view>
<view class="menu-item" bindtap="about">
<view class="menu-left">
<text class="menu-icon"></text>
<text class="menu-text">关于我们</text>
</view>
<view class="menu-right">
<text class="menu-arrow">></text>
</view>
</view>
</view>
</view>
<!-- 退出登录 -->
<view class="logout-section" wx:if="{{userInfo.id}}">
<button class="logout-btn" bindtap="logout">退出登录</button>
</view>
<!-- 底部留白 -->
<view class="bottom-space"></view>
</view>
<!-- 海报生成弹窗 -->
<view class="poster-modal" wx:if="{{showPoster}}" bindtap="closePoster">
<view class="poster-content" catchtap="stopPropagation">
<view class="poster-header">
<text class="poster-title">长按保存海报</text>
<text class="poster-close" bindtap="closePoster">×</text>
</view>
<canvas canvas-id="posterCanvas" class="poster-canvas"></canvas>
<button class="btn-primary save-poster-btn" bindtap="savePoster">
保存到相册
</button>
</view>
</view>

View File

@@ -0,0 +1,422 @@
/* pages/my/my.wxss */
.my-container {
padding: 32rpx 32rpx 160rpx;
background: linear-gradient(180deg, #000000 0%, #0a0a0a 100%);
}
/* 用户卡片 */
.user-card {
padding: 40rpx 32rpx;
margin-bottom: 24rpx;
border-radius: 32rpx;
}
.user-header {
display: flex;
align-items: center;
margin-bottom: 32rpx;
}
.user-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
margin-right: 24rpx;
border: 4rpx solid rgba(255, 77, 79, 0.5);
}
.user-info {
flex: 1;
}
.user-name {
font-size: 36rpx;
font-weight: 600;
color: #ffffff;
margin-bottom: 8rpx;
}
.user-id {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.5);
}
.vip-badge {
padding: 8rpx 20rpx;
background: linear-gradient(135deg, #FF4D4F 0%, #FF7875 100%);
border-radius: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(255, 77, 79, 0.4);
}
.vip-text {
font-size: 24rpx;
color: #ffffff;
font-weight: 600;
}
/* 用户统计 */
.user-stats {
display: flex;
align-items: center;
padding-top: 32rpx;
border-top: 2rpx solid rgba(255, 255, 255, 0.1);
}
.stat-item {
flex: 1;
text-align: center;
}
.stat-value {
font-size: 40rpx;
font-weight: 700;
color: #FF4D4F;
margin-bottom: 8rpx;
}
.stat-label {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.6);
}
.stat-divider {
width: 2rpx;
height: 60rpx;
background: rgba(255, 255, 255, 0.1);
}
/* 分销中心 */
.referral-section {
margin-bottom: 24rpx;
padding: 32rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
}
.section-title {
display: flex;
align-items: center;
gap: 12rpx;
}
.title-icon {
font-size: 32rpx;
}
.title-text {
font-size: 36rpx;
font-weight: 600;
color: #ffffff;
}
.referral-status {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 20rpx;
background: rgba(255, 77, 79, 0.2);
border-radius: 20rpx;
}
.status-text {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.7);
}
.status-value {
font-size: 28rpx;
font-weight: 700;
color: #FF4D4F;
}
/* 收益概览 */
.earnings-overview {
padding: 32rpx;
background: rgba(255, 77, 79, 0.1);
border-radius: 24rpx;
border: 2rpx solid rgba(255, 77, 79, 0.2);
margin-bottom: 24rpx;
}
.earnings-main {
text-align: center;
margin-bottom: 24rpx;
}
.earnings-label {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 12rpx;
}
.earnings-amount {
font-size: 64rpx;
font-weight: 700;
color: #FF4D4F;
letter-spacing: 2rpx;
}
.earnings-sub {
display: flex;
justify-content: space-around;
padding-top: 24rpx;
border-top: 2rpx solid rgba(255, 255, 255, 0.1);
}
.sub-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8rpx;
}
.sub-label {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.5);
}
.sub-value {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
/* 快速操作 */
.referral-actions {
display: flex;
gap: 16rpx;
margin-bottom: 32rpx;
}
.action-btn {
flex: 1;
font-size: 28rpx;
padding: 24rpx;
}
/* 推广数据 */
.referral-stats {
display: flex;
justify-content: space-around;
padding: 32rpx 0;
border-top: 2rpx solid rgba(255, 255, 255, 0.1);
border-bottom: 2rpx solid rgba(255, 255, 255, 0.1);
margin-bottom: 24rpx;
}
.referral-stat-item {
text-align: center;
}
.stat-number {
font-size: 40rpx;
font-weight: 700;
color: #FF4D4F;
margin-bottom: 8rpx;
}
.stat-name {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.6);
}
/* 邀请码 */
.invite-code-section {
padding: 24rpx;
background: rgba(255, 255, 255, 0.05);
border-radius: 16rpx;
}
.invite-label {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 12rpx;
}
.invite-code-box {
display: flex;
align-items: center;
justify-content: space-between;
}
.invite-code {
font-size: 40rpx;
font-weight: 700;
color: #FF4D4F;
letter-spacing: 4rpx;
font-family: 'Courier New', monospace;
}
.copy-btn {
padding: 12rpx 32rpx;
background: rgba(255, 77, 79, 0.2);
color: #FF7875;
border: none;
border-radius: 12rpx;
font-size: 26rpx;
font-weight: 600;
}
/* 功能菜单 */
.menu-section {
margin-bottom: 24rpx;
}
.menu-group {
padding: 0;
margin-bottom: 24rpx;
}
.menu-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
transition: background 0.3s;
}
.menu-item:active {
background: rgba(255, 255, 255, 0.05);
}
.menu-left {
display: flex;
align-items: center;
gap: 20rpx;
}
.menu-icon {
font-size: 40rpx;
}
.menu-text {
font-size: 30rpx;
color: #ffffff;
}
.menu-right {
display: flex;
align-items: center;
gap: 16rpx;
}
.menu-badge {
min-width: 32rpx;
height: 32rpx;
padding: 0 8rpx;
background: #FF4D4F;
border-radius: 16rpx;
font-size: 20rpx;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.menu-arrow {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.3);
}
.menu-divider {
height: 2rpx;
background: rgba(255, 255, 255, 0.05);
margin: 0 32rpx;
}
/* 退出登录 */
.logout-section {
padding: 0 32rpx;
margin-top: 48rpx;
}
.logout-btn {
width: 100%;
padding: 28rpx;
background: rgba(255, 255, 255, 0.05);
color: rgba(255, 255, 255, 0.6);
border: 2rpx solid rgba(255, 255, 255, 0.1);
border-radius: 16rpx;
font-size: 30rpx;
}
.logout-btn:active {
background: rgba(255, 255, 255, 0.08);
}
.bottom-space {
height: 40rpx;
}
/* 海报弹窗 */
.poster-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.9);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
animation: fadeIn 0.3s;
}
.poster-content {
width: 90%;
max-width: 600rpx;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20rpx);
border-radius: 32rpx;
padding: 32rpx;
animation: slideUp 0.4s ease-out;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(100rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.poster-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.poster-title {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
}
.poster-close {
font-size: 56rpx;
color: rgba(255, 255, 255, 0.6);
line-height: 1;
}
.poster-canvas {
width: 100%;
height: 800rpx;
background: #ffffff;
border-radius: 16rpx;
margin-bottom: 24rpx;
}
.save-poster-btn {
width: 100%;
}