第一次提交:微信小程序前端最新完整代码

This commit is contained in:
XingQue
2026-06-12 21:55:06 +08:00
commit 84be8489b4
330 changed files with 74263 additions and 0 deletions

View File

@@ -0,0 +1,393 @@
// pages/guanshi-paihang/guanshi-paihang.js
const app = getApp()
import request from '../../utils/request.js'
Page({
data: {
// 页面加载状态
jiazaiZhuangtai: true,
// 排行榜类型1=今日邀请2=今月邀请
paihangLeixing: 1,
// 榜单数据
paihangShuju: [],
// 是否展示真实数据(后端控制)
xianshiZhenshiShuju: false,
// 虚拟数据(用于当后端不允许展示时)
xuniShuju: [],
// 按钮防抖控制
btnFangdou: false,
// OSS图片基础URL从全局变量获取
ossImageUrl: '',
// 默认头像相对路径需要与OSS基础URL拼接
morentouxiang: '',
// 用户类型1=打手2=管事3=商家(当前页面固定为管事)
yonghuLeixing: 2,
// 前三名特殊数据
qiansanMing: [],
// 动画相关
crownAnimation: null,
// 卡片点击特效
flashCardIndex: -1,
flashCardType: '',
flashAnimation: null,
// 切换按钮选中状态
switchBgPosition: 0
},
onLoad() {
// 设置页面标题
wx.setNavigationBarTitle({
title: '管事排行榜'
})
// 初始化全局变量
this.setData({
ossImageUrl: app.globalData.ossImageUrl || '',
morentouxiang: app.globalData.morentouxiang || ''
})
// 初始化虚拟数据
this.initXuniShuju()
// 加载排行榜数据
this.huoquPaihangShuju()
// 开始皇冠动画
this.startCrownAnimation()
},
onShow() {
// 页面显示时恢复动画
this.registerNotificationComponent();
this.startCrownAnimation()
},
registerNotificationComponent() {
const app = getApp();
const notificationComp = this.selectComponent('#global-notification');
if (notificationComp && notificationComp.showNotification) {
console.log('🏪 商城页面注册通知组件');
app.globalData.globalNotification = {
show: (data) => notificationComp.showNotification(data),
hide: () => notificationComp.hideNotification()
};
}
},
onHide() {
// 页面隐藏时停止动画
this.stopCrownAnimation()
},
onUnload() {
// 页面卸载时停止动画
this.stopCrownAnimation()
},
// 初始化虚拟数据
initXuniShuju() {
const xuniShuju = []
const names = ['管事大神', '组织高手', '团队领袖', '精英管理', '运营达人',
'战略专家', '人才猎手', '组织核心', '管理大师', '招募高手']
for (let i = 0; i < 10; i++) {
xuniShuju.push({
mingci: i + 1,
touxiang: '',
nicheng: names[i] || `虚拟管事${i + 1}`,
uid: `G${100000 + i}`,
jine: (88 - i * 7).toString(), // 管事显示的是数量,不是金额
jineClass: 'normal' // 金额样式
})
}
this.setData({ xuniShuju })
},
// 开始皇冠动画
startCrownAnimation() {
this.stopCrownAnimation()
const animation = wx.createAnimation({
duration: 800,
timingFunction: 'ease-in-out'
})
let scale = 1
const animate = () => {
scale = scale === 1 ? 1.15 : 1
animation.scale(scale).step({
duration: 800,
timingFunction: 'ease-in-out'
})
this.setData({
crownAnimation: animation.export()
})
this.data.crownAnimationTimer = setTimeout(() => {
animate()
}, 800)
}
animate()
},
// 停止皇冠动画
stopCrownAnimation() {
if (this.data.crownAnimationTimer) {
clearTimeout(this.data.crownAnimationTimer)
this.setData({
crownAnimationTimer: null
})
}
},
// 卡片点击特效
handleCardTap(e) {
const index = e.currentTarget.dataset.index
const type = e.currentTarget.dataset.type // 'top3' 或 'normal'
// 创建闪光动画
const animation = wx.createAnimation({
duration: 300,
timingFunction: 'ease-out'
})
// 快速闪光效果
animation.opacity(0.9).step({
duration: 50,
timingFunction: 'linear'
})
animation.opacity(1).step({
duration: 250,
timingFunction: 'ease-out'
})
this.setData({
flashCardIndex: index,
flashCardType: type,
flashAnimation: animation.export()
})
// 300ms后重置闪光状态
setTimeout(() => {
this.setData({
flashCardIndex: -1,
flashCardType: ''
})
}, 300)
},
// 获取排行榜数据
async huoquPaihangShuju() {
this.setData({
jiazaiZhuangtai: true
})
try {
// 准备请求参数
const requestData = {
leixing: this.data.paihangLeixing,
yonghu_leixing: this.data.yonghuLeixing
}
// 使用封装的request发送请求
const res = await request({
url: '/peizhi/dsph',
method: 'POST',
data: requestData,
header: {
'content-type': 'application/json'
}
})
// 处理返回数据
if (res && res.data && res.data.code === 0) {
const responseData = res.data.data
// 检查后端是否允许展示
if (responseData.xianshi && responseData.paihang_list && responseData.paihang_list.length > 0) {
// 处理头像URL拼接和金额样式
const processedList = this.processData(responseData.paihang_list)
// 提取前三名特殊展示
const qiansanMing = processedList.slice(0, 3)
const qitaPaihang = processedList.slice(3)
this.setData({
paihangShuju: qitaPaihang,
qiansanMing: qiansanMing,
xianshiZhenshiShuju: true,
jiazaiZhuangtai: false
})
} else {
// 后端不允许展示或数据不足,显示虚拟数据
this.xianshiXuniShuju()
}
} else {
// 请求失败,显示虚拟数据
const errorMsg = res && res.data ? (res.data.msg || '获取数据失败') : '网络请求失败'
wx.showToast({
title: errorMsg,
icon: 'none',
duration: 2000
})
this.xianshiXuniShuju()
}
} catch (error) {
console.error('获取排行榜数据失败:', error)
wx.showToast({
title: '网络请求异常,请重试',
icon: 'none',
duration: 2000
})
this.xianshiXuniShuju()
}
},
// 处理数据(头像拼接和金额样式)
processData(list) {
const { ossImageUrl, morentouxiang } = this.data
return list.map(item => {
// 优先使用返回的头像URL
let finalTouxiang = item.touxiang
// 如果返回的头像为空,使用默认头像
if (!finalTouxiang && morentouxiang) {
finalTouxiang = morentouxiang
}
// 拼接完整的URL
let fullTouxiangUrl = ''
if (finalTouxiang && ossImageUrl) {
// 确保路径不以斜杠开头
let touxiangPath = finalTouxiang
if (touxiangPath.startsWith('/')) {
touxiangPath = touxiangPath.substring(1)
}
fullTouxiangUrl = ossImageUrl + touxiangPath
}
// 处理数量样式(管事显示的是数量,不是金额)
const jine = parseInt(item.jine || 0)
let jineClass = 'normal'
const jineStr = jine.toString() // 管事显示整数数量
// 判断数量位数
if (jineStr.length >= 5) { // 5位数及以上
jineClass = 'very-small'
} else if (jineStr.length >= 4) { // 4位数
jineClass = 'small'
} else if (jineStr.length >= 3) { // 3位数
jineClass = 'medium'
}
return {
...item,
full_touxiang: fullTouxiangUrl,
jine: jineStr,
jineClass: jineClass
}
})
},
// 显示虚拟数据
xianshiXuniShuju() {
const processedList = this.processData(this.data.xuniShuju)
const qiansanMing = processedList.slice(0, 3)
const qitaPaihang = processedList.slice(3)
this.setData({
paihangShuju: qitaPaihang,
qiansanMing: qiansanMing,
xianshiZhenshiShuju: false,
jiazaiZhuangtai: false
})
},
// 切换排行榜类型(今日/今月)
qiehuangPaihangLeixing(e) {
// 防抖处理:防止连续点击
if (this.data.btnFangdou) return
const leixing = e.currentTarget.dataset.leixing
if (leixing == this.data.paihangLeixing) return
// 设置防抖状态
this.setData({
btnFangdou: true
})
// 更新切换按钮位置
this.setData({
paihangLeixing: leixing,
switchBgPosition: leixing == 1 ? 0 : 1
})
// 重新加载数据
this.huoquPaihangShuju()
// 1秒后解除防抖
setTimeout(() => {
this.setData({
btnFangdou: false
})
}, 1000)
},
// 用户下拉刷新
onPullDownRefresh() {
this.huoquPaihangShuju()
wx.stopPullDownRefresh()
},
// 图片加载失败处理
tupianJiazaiShibai(e) {
const index = e.currentTarget.dataset.index
const type = e.currentTarget.dataset.type // 'top3' 或 'normal'
// 使用默认头像
const { ossImageUrl, morentouxiang } = this.data
let defaultUrl = ''
if (morentouxiang && ossImageUrl) {
let defaultPath = morentouxiang
if (defaultPath.startsWith('/')) {
defaultPath = defaultPath.substring(1)
}
defaultUrl = ossImageUrl + defaultPath
}
if (type === 'top3') {
// 前三名头像加载失败
const key = `qiansanMing[${index}].full_touxiang`
this.setData({
[key]: defaultUrl
})
} else {
// 普通排名头像加载失败
const key = `paihangShuju[${index}].full_touxiang`
this.setData({
[key]: defaultUrl
})
}
}
})

View File

@@ -0,0 +1,12 @@
{
"usingComponents": {
"global-notification": "/components/global-notification/global-notification"
},
"navigationBarTitleText": "管事排行榜",
"navigationBarBackgroundColor": "#000000",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": false,
"backgroundColor": "#000000",
"backgroundTextStyle": "dark",
"onReachBottomDistance": 50
}

View File

@@ -0,0 +1,289 @@
<!-- pages/guanshi-paihang/guanshi-paihang.wxml -->
<view class="guanshi-paihang-page">
<!-- 赛博朋克背景元素 -->
<view class="cyber-bg">
<!-- 网格线 -->
<view class="cyber-grid"></view>
<!-- 扫描线 -->
<view class="cyber-scanline"></view>
<!-- 流动数据流 -->
<view class="data-streams">
<view class="stream stream-1"></view>
<view class="stream stream-2"></view>
<view class="stream stream-3"></view>
</view>
<!-- 浮动粒子 -->
<view class="floating-particles">
<view class="particle" wx:for="{{12}}" wx:key="index"></view>
</view>
</view>
<!-- 页面头部 -->
<view class="page-header">
<!-- 标题 -->
<view class="title-container">
<text class="main-title">管事排行榜</text>
<view class="title-line"></view>
<text class="sub-title">GUANSHI RANKING</text>
</view>
<!-- 切换按钮 -->
<view class="toggle-container">
<view class="toggle-bg" style="transform: translateX({{paihangLeixing == 1 ? '0' : '100%'}});"></view>
<view
class="toggle-btn {{paihangLeixing == 1 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
data-leixing="1"
bindtap="qiehuangPaihangLeixing"
>
<text class="toggle-text">今日充值人数</text>
<view class="toggle-line {{paihangLeixing == 1 ? 'active' : ''}}"></view>
</view>
<view
class="toggle-btn {{paihangLeixing == 2 ? 'active' : ''}} {{btnFangdou ? 'disabled' : ''}}"
data-leixing="2"
bindtap="qiehuangPaihangLeixing"
>
<text class="toggle-text">今月充值人数</text>
<view class="toggle-line {{paihangLeixing == 2 ? 'active' : ''}}"></view>
</view>
</view>
</view>
<!-- 加载状态 -->
<view wx:if="{{jiazaiZhuangtai}}" class="loading-state">
<view class="loading-content">
<view class="loading-spinner">
<view class="spinner-outer"></view>
<view class="spinner-inner"></view>
<view class="spinner-core"></view>
</view>
<text class="loading-text">数据加载中</text>
<text class="loading-sub">Connecting to server...</text>
</view>
</view>
<!-- 排行榜内容 -->
<view wx:else class="ranking-content">
<!-- 虚拟数据提示 -->
<view wx:if="{{!xianshiZhenshiShuju}}" class="demo-notice">
<view class="notice-icon">📡</view>
<view class="notice-content">
<text class="notice-title">排行榜数据准备中</text>
<text class="notice-desc">当前显示为模拟数据,实时排名即将开放</text>
</view>
<view class="notice-glow"></view>
</view>
<!-- ========== 前三名区域 ========== -->
<view class="top-three-section" wx:if="{{qiansanMing.length > 0}}">
<!-- 第二名 -->
<view class="rank-card rank-2 {{flashCardIndex == 1 && flashCardType == 'top3' ? 'flash' : ''}}"
animation="{{flashCardIndex == 1 && flashCardType == 'top3' ? flashAnimation : ''}}"
data-index="1" data-type="top3" bindtap="handleCardTap">
<view class="podium-base podium-silver">
<view class="podium-glow"></view>
<text class="podium-number">2</text>
</view>
<view class="rank-content">
<!-- 头像容器 -->
<view class="avatar-frame frame-silver">
<view class="avatar-container">
<image class="avatar-image" src="{{qiansanMing[1] ? qiansanMing[1].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
<view class="avatar-halo halo-silver"></view>
<view class="avatar-sparkles">
<view class="sparkle s1"></view>
<view class="sparkle s2"></view>
<view class="sparkle s3"></view>
</view>
</view>
<view class="rank-badge badge-silver">2</view>
</view>
<!-- 用户信息 -->
<view class="user-info-card">
<view class="info-header">
<text class="user-name">{{qiansanMing[1] ? qiansanMing[1].nicheng : '等待上榜'}}</text>
</view>
<view class="info-body">
<view class="uid-row">
<text class="uid-label">ID:</text>
<text class="uid-value">{{qiansanMing[1] ? qiansanMing[1].uid : '----'}}</text>
</view>
<view class="income-row">
<text class="income-label">充值大手:</text>
<view class="income-value">
<text class="amount {{qiansanMing[1] ? qiansanMing[1].jineClass : ''}}">{{qiansanMing[1] ? qiansanMing[1].jine : '0'}}</text>
<text class="unit">人</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 第一名 -->
<view class="rank-card rank-1 {{flashCardIndex == 0 && flashCardType == 'top3' ? 'flash' : ''}}"
animation="{{flashCardIndex == 0 && flashCardType == 'top3' ? flashAnimation : ''}}"
data-index="0" data-type="top3" bindtap="handleCardTap">
<!-- 皇冠 -->
<view class="crown-container" animation="{{crownAnimation}}">
<view class="crown">
<text class="crown-icon">👑</text>
<view class="crown-rays">
<view class="ray ray-1"></view>
<view class="ray ray-2"></view>
<view class="ray ray-3"></view>
<view class="ray ray-4"></view>
<view class="ray ray-5"></view>
<view class="ray ray-6"></view>
</view>
<view class="crown-glow"></view>
</view>
</view>
<view class="podium-base podium-gold">
<view class="podium-glow"></view>
<text class="podium-number">1</text>
</view>
<view class="rank-content">
<!-- 头像容器 -->
<view class="avatar-frame frame-gold">
<view class="avatar-container">
<image class="avatar-image" src="{{qiansanMing[0] ? qiansanMing[0].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
<view class="avatar-halo halo-gold"></view>
<view class="avatar-sparkles">
<view class="sparkle s1"></view>
<view class="sparkle s2"></view>
<view class="sparkle s3"></view>
<view class="sparkle s4"></view>
</view>
</view>
<view class="rank-badge badge-gold">1</view>
</view>
<!-- 用户信息 -->
<view class="user-info-card">
<view class="info-header">
<text class="user-name">{{qiansanMing[0] ? qiansanMing[0].nicheng : '等待上榜'}}</text>
</view>
<view class="info-body">
<view class="uid-row">
<text class="uid-label">ID:</text>
<text class="uid-value">{{qiansanMing[0] ? qiansanMing[0].uid : '----'}}</text>
</view>
<view class="income-row">
<text class="income-label">充值大手:</text>
<view class="income-value">
<text class="amount {{qiansanMing[0] ? qiansanMing[0].jineClass : ''}}">{{qiansanMing[0] ? qiansanMing[0].jine : '0'}}</text>
<text class="unit">人</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 第三名 -->
<view class="rank-card rank-3 {{flashCardIndex == 2 && flashCardType == 'top3' ? 'flash' : ''}}"
animation="{{flashCardIndex == 2 && flashCardType == 'top3' ? flashAnimation : ''}}"
data-index="2" data-type="top3" bindtap="handleCardTap">
<view class="podium-base podium-bronze">
<view class="podium-glow"></view>
<text class="podium-number">3</text>
</view>
<view class="rank-content">
<!-- 头像容器 -->
<view class="avatar-frame frame-bronze">
<view class="avatar-container">
<image class="avatar-image" src="{{qiansanMing[2] ? qiansanMing[2].full_touxiang : ''}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
<view class="avatar-halo halo-bronze"></view>
<view class="avatar-sparkles">
<view class="sparkle s1"></view>
<view class="sparkle s2"></view>
<view class="sparkle s3"></view>
</view>
</view>
<view class="rank-badge badge-bronze">3</view>
</view>
<!-- 用户信息 -->
<view class="user-info-card">
<view class="info-header">
<text class="user-name">{{qiansanMing[2] ? qiansanMing[2].nicheng : '等待上榜'}}</text>
</view>
<view class="info-body">
<view class="uid-row">
<text class="uid-label">ID:</text>
<text class="uid-value">{{qiansanMing[2] ? qiansanMing[2].uid : '----'}}</text>
</view>
<view class="income-row">
<text class="income-label">充值大手:</text>
<view class="income-value">
<text class="amount {{qiansanMing[2] ? qiansanMing[2].jineClass : ''}}">{{qiansanMing[2] ? qiansanMing[2].jine : '0'}}</text>
<text class="unit">人</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- ========== 其他排名列表 ========== -->
<view class="other-ranks-section" wx:if="{{paihangShuju.length > 0}}">
<view class="section-title">
<view class="title-line"></view>
<text class="title-text">其他排名</text>
<view class="title-line"></view>
</view>
<view class="rank-list">
<view class="rank-item {{flashCardIndex == index && flashCardType == 'normal' ? 'flash' : ''}}"
wx:for="{{paihangShuju}}" wx:key="index"
animation="{{flashCardIndex == index && flashCardType == 'normal' ? flashAnimation : ''}}"
data-index="{{index}}" data-type="normal" bindtap="handleCardTap">
<view class="rank-number">
<text class="number-text">{{xianshiZhenshiShuju ? index + 4 : index + 1}}</text>
<view class="number-glow"></view>
</view>
<view class="rank-avatar">
<image class="rank-avatar-img" src="{{item.full_touxiang}}" mode="aspectFill" binderror="tupianJiazaiShibai"></image>
<view class="rank-avatar-halo"></view>
</view>
<view class="rank-info">
<text class="rank-name">{{item.nicheng}}</text>
<text class="rank-uid">UID: {{item.uid}}</text>
</view>
<view class="rank-income">
<text class="income-amount {{item.jineClass}}">{{item.jine}}</text>
<text class="income-unit">人</text>
<view class="income-glow"></view>
</view>
<view class="rank-hover"></view>
</view>
</view>
</view>
<!-- 空状态 -->
<view wx:if="{{xianshiZhenshiShuju && paihangShuju.length === 0 && qiansanMing.length === 0}}" class="empty-state">
<view class="empty-icon">🏆</view>
<text class="empty-title">暂无排名数据</text>
<text class="empty-desc">成为第一个登榜的管事吧</text>
</view>
</view>
</view>
<global-notification id="global-notification" />

File diff suppressed because it is too large Load Diff