From a21b1d2426fac3b98ed97ca0c7f44ff244ae7ab8 Mon Sep 17 00:00:00 2001 From: XingQue Date: Sat, 27 Jun 2026 00:40:42 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=8E=92=E8=A1=8C=E6=A6=9C?= =?UTF-8?q?=E9=A1=B5=EF=BC=9A=E5=9B=9B=E8=A7=92=E8=89=B2=E4=B8=83=E6=97=B6?= =?UTF-8?q?=E6=AE=B5=EF=BC=8C=E5=AF=B9=E6=8E=A5=20phbhqsj=20=E6=96=B0?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- miniprogram/app.js | 345 +++++++++++++++ .../pages/dashoupaihang/dashoupaihang.js | 262 +++++++++++ .../pages/dashoupaihang/dashoupaihang.json | 11 + .../pages/dashoupaihang/dashoupaihang.wxml | 127 ++++++ .../pages/dashoupaihang/dashoupaihang.wxss | 415 ++++++++++++++++++ .../pages/guanshipaihang/guanshipaihang.js | 6 + miniprogram/pages/sjpaihang/sjpaihang.js | 6 + miniprogram/utils/avatar.js | 19 + 8 files changed, 1191 insertions(+) create mode 100644 miniprogram/app.js create mode 100644 miniprogram/pages/dashoupaihang/dashoupaihang.js create mode 100644 miniprogram/pages/dashoupaihang/dashoupaihang.json create mode 100644 miniprogram/pages/dashoupaihang/dashoupaihang.wxml create mode 100644 miniprogram/pages/dashoupaihang/dashoupaihang.wxss create mode 100644 miniprogram/pages/guanshipaihang/guanshipaihang.js create mode 100644 miniprogram/pages/sjpaihang/sjpaihang.js create mode 100644 miniprogram/utils/avatar.js diff --git a/miniprogram/app.js b/miniprogram/app.js new file mode 100644 index 0000000..fb438a9 --- /dev/null +++ b/miniprogram/app.js @@ -0,0 +1,345 @@ +// app.js - 优化生产版本(修复重连机制和用户ID问题) +import GoEasy from './static/lib/goeasy-2.13.24.esm.min'; +const ChatCore = require('./utils/chat-core'); +import { check } from './utils/phone-auth'; + + +// ===== 角色 → 默认首页(与 custom-tab-bar 完全一致) ===== +const roleDefaultPage = { + normal: '/pages/index/index', + dashou: '/pages/dashouduan/dashouduan', + shangjia: '/pages/shangjiaduan/shangjiaduan', // 商家首页也是商城 + guanshi: '/pages/guanshiduan/guanshiduan', + zuzhang: '/pages/zuzhangduan/zuzhangduan', + kaoheguan: '/pages/kaoheguan/kaoheguan' +}; + +App({ + globalData: { + + hasShownPopupOnColdStart: false, + + apiBaseUrl: 'https://6ccy.top/hqhd', + ossImageUrl: '', + morentouxiang: '', + dashouguize: '', + paihangAssets: null, + + shangpinliebiao: [], + shangpinzhuanqu: [], + shangpinleixing: [], + shangpinlunbo: [], + shangpingonggao: '', + lunbozhanwei: '/images/lunbozhanwei.jpg', + + dingdanTiaoshu: { + daifuwu: 0, + fuwuzhong: 0, + yiwancheng: 0, + yituikuan: 0 + }, + + dashouqun: '', + dashouqunid: '', + guanshiqun: '', + guanshiqunid: '', + + appId:'wx2517043ca3f39677', + + shangjiastatus: 0, + dashoustatus: 0, + guanshistatus: 0, + dashouNicheng: '', + zhanghaoStatus: null, + dashouzhuangtai: null, + yongjin: null, + zonge: null, + yajin: null, + chenghao: '', + jinfen: null, + clumber: [{ + huiyuanid: '', + huiyuanming: '', + daoqi: '' + }], + chengjiaoliang: null, + zaixianZhuangtai: null, + + guanshi: { + nicheng: '', + uid: '', + touxiang: '', + gszhstatus: '', + yaoqingzongshu: 0, + fenyongzonge: '0.00', + fenyongtixian: '0.00' + }, + + shangjia: { + sjzhzhuangtai: '', + sjyue: '', + fadanzong: null, + tuikuanzong: null, + riliushui: '', + yueliushui: '' + }, + + liaotian_liebiao: [], + xshenfen: 1, + + goEasyConfig: null, + chatEnabled: false, + kefuConfig: { + link: '', + enterpriseId: '' + }, + + cosConfig: { + bucket: '', + region: 'ap-shanghai', + uploadPathPrefix: 'order/' + }, + + goEasyConnection: { + status: 'disconnected', + userId: '', + identityType: '', + lastConnectTime: 0, + autoReconnect: true, + reconnectAttempts: 0, + maxReconnectAttempts: 5, + heartbeatInterval: null, + cacheKeys: { + savedConnection: 'savedGoEasyConnection', + userId: 'goEasyUserId', + identityType: 'currentGoEasyIdentity', + connectTime: 'goEasyConnectTime' + }, + config: { + heartbeatInterval: 20000, + reconnectDelay: 3000, + offlineTimeout: 30000, + cacheValidityHours: 12 + } + }, + + messageManager: { + unreadTotal: 0, + unreadMap: {}, + latestMessages: [], + notificationQueue: [], + notificationVisible: false, + lastNotificationTime: 0, + notificationCooldown: 3000, + tabBarIndex: 2, + showTabBarBadge: true, + customTabBar: true, + tabBarBadgeText: 0, + soundEnabled: true, + vibrationEnabled: true, + doNotDisturb: false, + doNotDisturbStart: '22:00', + doNotDisturbEnd: '08:00', + notificationStyle: { + position: 'top', + duration: 3000, + backgroundColor: '#00f7ff', + textColor: '#ffffff', + borderRadius: '16rpx', + boxShadow: '0 10rpx 30rpx rgba(0, 247, 255, 0.3)' + }, + currentNotification: null, + cacheKeys: { + messageSettings: 'messageSettings', + unreadTotal: 'messageUnreadTotal', + latestMessages: 'latestMessages', + notificationMuted: 'notificationMuted' + } + }, + + pageState: { + currentPage: '', + isInChatPage: false, + currentChatId: '', + lastPageUpdate: 0 + }, + + eventListeners: {}, + debugMode: false, + currentUser: null, + currentRole: 'normal' // 当前角色,默认老板 + }, + + // ========== 仅修改 onLaunch,其余未动 ========== + async onLaunch() { + // ---------- ① 立即隐藏“返回首页”按钮 ---------- + wx.hideHomeButton(); + wx.onAppRoute(() => { + wx.hideHomeButton(); + }); + // 🆕 手机号认证检查 + + + // ---------- ② 恢复角色并跳转(不依赖网络) ---------- + const savedRole = wx.getStorageSync('currentRole') || 'normal'; + this.globalData.currentRole = savedRole; + + const targetPage = roleDefaultPage[savedRole] || '/pages/index/index'; + if (savedRole !== 'normal' || targetPage !== '/pages/index/index') { + setTimeout(() => { + wx.reLaunch({ url: targetPage }); + }, 0); + } + + // ---------- ③ 后台静默获取配置,成功后再初始化 GoEasy/IM ---------- + this.fetchDynamicConfig() + .then(config => { + this.applyDynamicConfig(config); + this.initGoEasyWithConfig(); + ChatCore.initGlobalMessageSystem(this); + this.initCurrentUser(); + this.bootstrapImListening(); + }) + .catch(error => { + console.error('获取动态配置失败:', error); + this.initGoEasyWithConfig(); + ChatCore.initGlobalMessageSystem(this); + this.initCurrentUser(); + }); + + try { + const needAuth = await check(); + if (needAuth) { + wx.reLaunch({ url: '/pages/phone-auth/phone-auth' }); + return; + } + } catch (e) {} + }, + + onShow() { + if (typeof this.ensureConnection === 'function') { + this.ensureConnection(); + } + }, + + bootstrapImListening() { + const uid = wx.getStorageSync('uid'); + if (!uid) return; + try { + this.ensureConnection(); + } catch (e) { + console.warn('IM 启动失败:', e); + } + }, + + + + + // 以下三个方法完全保持原样 + fetchDynamicConfig() { + return new Promise((resolve, reject) => { + wx.request({ + url: this.globalData.apiBaseUrl + '/peizhi/qdpzhq', + method: 'POST', + header: { 'content-type': 'application/json' }, + success: (res) => { + if (res.statusCode === 200 && res.data && res.data.code === 0) { + resolve(res.data.data); + } else { + reject(new Error(res.data?.msg || '接口返回错误')); + } + }, + fail: reject + }); + }); + }, + + applyDynamicConfig(config) { + if (config.cos) { + this.globalData.ossImageUrl = config.cos.ossImageUrl || ''; + this.globalData.cosConfig = { + bucket: config.cos.bucket || '', + region: config.cos.region || 'ap-shanghai', + uploadPathPrefix: config.cos.uploadPathPrefix || 'order/' + }; + } + if (config.goEasy) { + this.globalData.goEasyConfig = { + host: config.goEasy.host || 'hangzhou.goeasy.io', + appkey: config.goEasy.appkey || '' + }; + } + if (config.otherConfig) { + this.globalData.morentouxiang = config.otherConfig.morentouxiang || ''; + this.globalData.dashouguize = config.otherConfig.dashouguize || ''; + this.globalData.paihangAssets = config.otherConfig.paihangAssets || null; + } + if (config.kefu) { + this.globalData.kefuConfig = { + link: config.kefu.link || '', + enterpriseId: config.kefu.enterpriseId || '' + }; + } + }, + + initGoEasyWithConfig() { + const cfg = this.globalData.goEasyConfig; + if (!cfg || !cfg.appkey) { + console.error('GoEasy appkey 未配置,无法初始化'); + this.globalData.chatEnabled = false; + return; + } + try { + wx.goEasy = GoEasy.getInstance({ + host: cfg.host || 'hangzhou.goeasy.io', + appkey: cfg.appkey, + modules: ['im', 'pubsub'] + }); + wx.GoEasy = GoEasy; + const imReady = !!(wx.goEasy?.im && typeof wx.goEasy.im.on === 'function'); + this.globalData.chatEnabled = imReady; + if (!imReady) { + wx.goEasy = null; + } + } catch (e) { + console.warn('GoEasy 初始化失败:', e); + this.globalData.chatEnabled = false; + wx.goEasy = null; + } + }, + + initCurrentUser() { + const uid = wx.getStorageSync('uid'); + if (uid) { + this.globalData.currentUser = { + id: uid, + name: '用户' + uid.substring(0, 6), + avatar: this.globalData.ossImageUrl + this.globalData.morentouxiang + }; + } + }, + + emitEvent(eventName, data) { + if (this.globalData.eventListeners[eventName]) { + this.globalData.eventListeners[eventName].forEach(callback => { + try { callback(data); } catch (error) { console.error(error); } + }); + } + }, + + on(eventName, callback) { + if (!this.globalData.eventListeners[eventName]) { + this.globalData.eventListeners[eventName] = []; + } + this.globalData.eventListeners[eventName].push(callback); + }, + + off(eventName, callback) { + if (this.globalData.eventListeners[eventName]) { + const index = this.globalData.eventListeners[eventName].indexOf(callback); + if (index > -1) { + this.globalData.eventListeners[eventName].splice(index, 1); + } + } + } +}); \ No newline at end of file diff --git a/miniprogram/pages/dashoupaihang/dashoupaihang.js b/miniprogram/pages/dashoupaihang/dashoupaihang.js new file mode 100644 index 0000000..1bf4b2e --- /dev/null +++ b/miniprogram/pages/dashoupaihang/dashoupaihang.js @@ -0,0 +1,262 @@ +/** + * 统一排行榜(打手/管事/组长/商家) + * POST /yonghu/phbhqsj + */ +import request from '../../utils/request.js' +import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js' + +const RANK_API = '/yonghu/phbhqsj' + +const ROLE_LIST = [ + { key: 'dashou', label: '打手' }, + { key: 'guanshi', label: '管事' }, + { key: 'zuzhang', label: '组长' }, + { key: 'shangjia', label: '商家' }, +] + +const DATE_LIST = [ + { key: '今日', label: '今日' }, + { key: '本周', label: '本周' }, + { key: '本月', label: '本月' }, + { key: '总榜', label: '总榜' }, + { key: '昨日', label: '昨日' }, + { key: '上周', label: '上周' }, + { key: '上月', label: '上月' }, +] + +const ROLE_META = { + dashou: { + title: '打手排行榜', + sortField: 'chengjiao_zonge', + sortLabel: '成交总额', + mainType: 'money', + metrics: [ + { field: 'jiedan_zongliang', label: '接单量', type: 'int' }, + { field: 'jiedan_zonge', label: '接单额', type: 'money' }, + { field: 'chengjiao_zongliang', label: '成交量', type: 'int' }, + ], + }, + guanshi: { + title: '管事排行榜', + sortField: 'shouru_zonge', + sortLabel: '收入总额', + mainType: 'money', + metrics: [ + { field: 'yaoqing_dashou_shu', label: '邀请', type: 'int' }, + { field: 'chongzhi_dashou_shu', label: '充值', type: 'int' }, + ], + }, + zuzhang: { + title: '组长排行榜', + sortField: 'shouru_zonge', + sortLabel: '收入总额', + mainType: 'money', + metrics: [ + { field: 'yaoqing_guanshi_shu', label: '邀请', type: 'int' }, + { field: 'fenyong_jine', label: '分佣', type: 'money' }, + ], + }, + shangjia: { + title: '商家排行榜', + sortField: 'jiesuan_jine', + sortLabel: '成交总额', + mainType: 'money', + metrics: [ + { field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' }, + { field: 'paifa_dingdan_shu', label: '派单量', type: 'int' }, + { field: 'paifa_jine', label: '派单额', type: 'money' }, + ], + }, +} + +function buildAvatar(path, app) { + const def = getDefaultAvatarUrl(app) + if (!path) return def + return resolveAvatarUrl(path, app) || def +} + +Page({ + data: { + imgUrls: {}, + roleList: ROLE_LIST, + dateList: DATE_LIST, + currentRole: 'dashou', + currentDate: '今日', + roleMeta: ROLE_META.dashou, + sortLabel: '成交总额', + isLoading: true, + rankList: [], + topThree: [], + restList: [], + isEmpty: false, + defaultAvatar: '', + }, + + onLoad(options) { + const type = options.type || options.rankType || 'dashou' + const validRole = ROLE_META[type] ? type : 'dashou' + this.initPageAssets() + this.applyRole(validRole, false) + this.fetchRankList() + }, + + onPullDownRefresh() { + this.fetchRankList().finally(() => wx.stopPullDownRefresh()) + }, + + initPageAssets() { + this.syncDefaultAvatar() + const g = getApp().globalData + const assets = g.paihangAssets || {} + const base = (g.ossImageUrl || '') + (assets.basePath || 'beijing/paihangbang/') + this.setData({ + imgUrls: { + pageBg: base + (assets.pageBg || 'page-bg.jpg'), + cardBg: base + (assets.cardBg || 'list-card-bg.png'), + emptyIcon: base + (assets.emptyIcon || 'empty.png'), + refreshIcon: base + (assets.refreshIcon || 'icon-refresh.png'), + }, + }) + }, + + syncDefaultAvatar() { + const def = getDefaultAvatarUrl() + if (def) this.setData({ defaultAvatar: def }) + }, + + ensureAvatars() { + const def = getDefaultAvatarUrl() + if (!def) return + const oss = getApp().globalData.ossImageUrl || '' + const { rankList, topThree, restList } = this.data + if (!rankList.length) { + this.setData({ defaultAvatar: def }) + return + } + const isValid = (url) => url && typeof url === 'string' && (url.startsWith('http') || (oss && url.indexOf(oss) === 0)) + const fix = (item) => ({ ...item, avatar: isValid(item.avatar) ? item.avatar : def }) + this.setData({ + defaultAvatar: def, + rankList: rankList.map(fix), + topThree: topThree.map(fix), + restList: restList.map(fix), + }) + }, + + applyRole(role, reload = true) { + const meta = ROLE_META[role] + wx.setNavigationBarTitle({ title: meta.title }) + this.setData({ currentRole: role, roleMeta: meta, sortLabel: meta.sortLabel }) + if (reload) this.fetchRankList() + }, + + onRoleTap(e) { + const role = e.currentTarget.dataset.role + if (!role || role === this.data.currentRole) return + this.applyRole(role) + }, + + onDateTap(e) { + const date = e.currentTarget.dataset.date + if (!date || date === this.data.currentDate) return + this.setData({ currentDate: date }) + this.fetchRankList() + }, + + onRefreshTap() { + this.fetchRankList() + }, + + formatMoney(val) { + const n = parseFloat(val) + return Number.isNaN(n) ? '0.00' : n.toFixed(2) + }, + + formatInt(val) { + const n = parseInt(val, 10) + return Number.isNaN(n) ? '0' : String(n) + }, + + normalizeItem(raw, index, role) { + const meta = ROLE_META[role] + const app = getApp() + const uid = raw.yonghuid || raw.uid || '' + const nicheng = raw.nicheng || raw.nick || '用户' + const avatar = buildAvatar(raw.touxiang || raw.avatar, app) + const metrics = meta.metrics.map((m) => { + const v = raw[m.field] + return { + label: m.label, + value: m.type === 'money' ? this.formatMoney(v) : this.formatInt(v), + } + }) + const sortRaw = raw[meta.sortField] + const mainType = meta.mainType || 'money' + const mainValue = mainType === 'money' ? this.formatMoney(sortRaw) : this.formatInt(sortRaw) + return { + mingci: raw.mingci || index + 1, + uid, + nicheng, + avatar, + mainType, + mainPrefix: mainType === 'money' ? '¥' : '', + mainValue, + mainLabel: meta.sortLabel, + metrics, + } + }, + + async fetchRankList() { + this.setData({ isLoading: true, isEmpty: false }) + try { + const res = await request({ + url: RANK_API, + method: 'POST', + data: { shenfen: this.data.currentRole, riqi: this.data.currentDate }, + }) + const body = res?.data || {} + const ok = body.code === 0 || body.code === 200 + let list = ok && body.data ? (body.data.list || body.data.paihang_list || []) : [] + if (!Array.isArray(list)) list = [] + const role = this.data.currentRole + const normalized = list.slice(0, 50).map((item, i) => this.normalizeItem(item, i, role)) + this.setData({ + rankList: normalized, + topThree: normalized.slice(0, 3), + restList: normalized.slice(3), + isEmpty: normalized.length === 0, + isLoading: false, + }) + this.ensureAvatars() + } catch (e) { + console.error('排行榜加载失败', e) + wx.showToast({ title: '加载失败', icon: 'none' }) + this.setData({ rankList: [], topThree: [], restList: [], isEmpty: true, isLoading: false }) + } + }, + + onAvatarError(e) { + const { zone, index } = e.currentTarget.dataset + const fallback = getDefaultAvatarUrl() + if (!fallback) return + const key = zone === 'top' ? `topThree[${index}].avatar` : `restList[${index}].avatar` + this.setData({ [key]: fallback }) + }, + + registerNotificationComponent() { + const app = getApp() + const comp = this.selectComponent('#global-notification') + if (comp?.showNotification) { + app.globalData.globalNotification = { + show: (d) => comp.showNotification(d), + hide: () => comp.hideNotification(), + } + } + }, + + onShow() { + this.syncDefaultAvatar() + this.ensureAvatars() + this.registerNotificationComponent() + }, +}) diff --git a/miniprogram/pages/dashoupaihang/dashoupaihang.json b/miniprogram/pages/dashoupaihang/dashoupaihang.json new file mode 100644 index 0000000..2d19320 --- /dev/null +++ b/miniprogram/pages/dashoupaihang/dashoupaihang.json @@ -0,0 +1,11 @@ +{ + "usingComponents": { + "global-notification": "/components/global-notification/global-notification" + }, + "navigationBarTitleText": "排行榜", + "navigationBarBackgroundColor": "#0d1117", + "navigationBarTextStyle": "white", + "enablePullDownRefresh": true, + "backgroundColor": "#0d1117", + "backgroundTextStyle": "light" +} diff --git a/miniprogram/pages/dashoupaihang/dashoupaihang.wxml b/miniprogram/pages/dashoupaihang/dashoupaihang.wxml new file mode 100644 index 0000000..60b533c --- /dev/null +++ b/miniprogram/pages/dashoupaihang/dashoupaihang.wxml @@ -0,0 +1,127 @@ + + + + + + {{roleMeta.title}} + + + + + + + {{item.label}} + + + + {{item.label}} + + {{currentDate}} · 按{{sortLabel}} · TOP50 + + + + + 加载中 + + + + + 暂无排行数据 + + + + + + + + 2 + + + + {{topThree[1].nicheng}} + ID {{topThree[1].uid}} + + {{topThree[1].mainPrefix}}{{topThree[1].mainValue}} + {{topThree[1].mainLabel}} + + + {{m.label}} {{m.value}} + + + + + + 1 + + + + {{topThree[0].nicheng}} + ID {{topThree[0].uid}} + + {{topThree[0].mainPrefix}}{{topThree[0].mainValue}} + {{topThree[0].mainLabel}} + + + {{m.label}} {{m.value}} + + + + + + 3 + + + + {{topThree[2].nicheng}} + ID {{topThree[2].uid}} + + {{topThree[2].mainPrefix}}{{topThree[2].mainValue}} + {{topThree[2].mainLabel}} + + + {{m.label}} {{m.value}} + + + + + + + + + 完整榜单 + 第 4 - {{rankList.length}} 名 + + + + + + {{item.mingci}} + + + {{item.nicheng}} + ID {{item.uid}} + + {{m.label}} {{m.value}} + + + + {{item.mainPrefix}}{{item.mainValue}} + {{item.mainLabel}} + + + + + + + + + + diff --git a/miniprogram/pages/dashoupaihang/dashoupaihang.wxss b/miniprogram/pages/dashoupaihang/dashoupaihang.wxss new file mode 100644 index 0000000..748f24e --- /dev/null +++ b/miniprogram/pages/dashoupaihang/dashoupaihang.wxss @@ -0,0 +1,415 @@ +page { + background: #0d1117; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', sans-serif; +} + +.rank-page { + min-height: 100vh; + position: relative; +} + +.page-bg { + position: fixed; + top: 0; left: 0; + width: 100%; height: 100%; + z-index: 0; +} + +.top-bar { + position: relative; + z-index: 10; + padding: 16rpx 28rpx 20rpx; +} + +.top-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20rpx; +} + +.page-title { + font-size: 38rpx; + font-weight: 700; + color: #fff; +} + +.refresh-wrap { + width: 60rpx; height: 60rpx; + border-radius: 50%; + background: rgba(255,255,255,0.14); + display: flex; + align-items: center; + justify-content: center; +} + +.refresh-ico { + width: 32rpx; height: 32rpx; + opacity: 0.8; +} + +.role-scroll { + width: 100%; + white-space: nowrap; + margin-bottom: 16rpx; +} + +.role-line { + display: inline-flex; + gap: 12rpx; +} + +.role-chip { + display: inline-block; + padding: 12rpx 28rpx; + border-radius: 999rpx; + font-size: 26rpx; + color: rgba(255,255,255,0.65); + background: rgba(20, 26, 40, 0.75); + border: 1rpx solid rgba(255,255,255,0.12); +} + +.role-chip.on { + color: #fff; + font-weight: 600; + background: rgba(107, 163, 247, 0.45); + border-color: rgba(107, 163, 247, 0.65); +} + +.date-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 10rpx; + margin-bottom: 12rpx; +} + +.date-chip { + text-align: center; + padding: 14rpx 0; + border-radius: 14rpx; + font-size: 24rpx; + color: rgba(255,255,255,0.65); + background: rgba(20, 26, 40, 0.72); + border: 1rpx solid rgba(255,255,255,0.08); +} + +.date-chip.on { + color: #A8CCFF; + font-weight: 600; + background: rgba(107, 163, 247, 0.35); + border-color: rgba(107, 163, 247, 0.55); +} + +.sort-tip { + font-size: 22rpx; + color: rgba(255,255,255,0.3); +} + +.state-wrap { + position: relative; + z-index: 5; + display: flex; + flex-direction: column; + align-items: center; + padding: 140rpx 0; + color: rgba(255,255,255,0.45); + font-size: 28rpx; +} + +.loader { + width: 48rpx; height: 48rpx; + border: 3rpx solid rgba(255,255,255,0.12); + border-top-color: #6BA3F7; + border-radius: 50%; + animation: spin 0.7s linear infinite; + margin-bottom: 20rpx; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.state-img { + width: 160rpx; height: 160rpx; + margin-bottom: 20rpx; + opacity: 0.65; +} + +.body-scroll { + position: relative; + z-index: 5; + height: calc(100vh - 300rpx); +} + +.podium-panel { + margin: 8rpx 24rpx 24rpx; + padding: 28rpx 12rpx 0; + border-radius: 28rpx; + background: rgba(14, 18, 30, 0.88); + border: 1rpx solid rgba(255, 255, 255, 0.1); +} + +.podium-cols { + display: flex; + align-items: flex-end; + justify-content: center; + gap: 10rpx; +} + +.p-col { + flex: 1; + max-width: 220rpx; + display: flex; + flex-direction: column; + align-items: center; +} + +.p-first { max-width: 250rpx; margin-bottom: 16rpx; } + +.p-badge { + width: 44rpx; height: 44rpx; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 14rpx; + font-size: 24rpx; + font-weight: 800; +} + +.p-first .p-badge { width: 52rpx; height: 52rpx; font-size: 28rpx; } + +.badge-first { + color: #fff; + background: linear-gradient(145deg, #6BA3F7, #4A7FD4); +} + +.badge-silver { + color: #fff; + background: linear-gradient(145deg, #A8B4C4, #7A8899); +} + +.badge-bronze { + color: #fff; + background: linear-gradient(145deg, #C4A882, #9A7858); +} + +.p-avatar-wrap { + border-radius: 50%; + padding: 4rpx; + margin-bottom: 12rpx; +} + +.wrap-first { padding: 5rpx; background: linear-gradient(145deg, #8EB8FF, #5B8FD8); } +.wrap-silver { background: linear-gradient(145deg, #C8D0DA, #909AA8); } +.wrap-bronze { background: linear-gradient(145deg, #D4B896, #A88860); } + +.p-avatar { + width: 100rpx; height: 100rpx; + border-radius: 50%; + display: block; + background: #1a2030; +} + +.p-avatar-lg { width: 120rpx; height: 120rpx; } + +.p-name { + font-size: 26rpx; + font-weight: 600; + color: rgba(255,255,255,0.92); + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.p-name-first { font-size: 28rpx; color: #fff; } + +.p-uid { + margin-top: 4rpx; + font-size: 20rpx; + color: rgba(255,255,255,0.35); +} + +.p-amount { margin: 12rpx 0 10rpx; text-align: center; } + +.p-money { + display: block; + font-size: 30rpx; + font-weight: 700; + color: #8EB8FF; +} + +.p-money-first { font-size: 34rpx; color: #A8CCFF; } + +.p-label { + display: block; + margin-top: 2rpx; + font-size: 20rpx; + color: rgba(255,255,255,0.35); +} + +.p-metrics { + display: flex; + flex-wrap: wrap; + gap: 6rpx; + justify-content: center; + margin-bottom: 16rpx; + min-height: 36rpx; +} + +.p-metric { + font-size: 18rpx; + color: rgba(255,255,255,0.55); + background: rgba(255,255,255,0.1); + padding: 4rpx 10rpx; + border-radius: 8rpx; +} + +.p-pedestal { + width: 88%; + border-radius: 20rpx 20rpx 0 0; +} + +.pedestal-first { + height: 100rpx; + background: linear-gradient(180deg, rgba(107,163,247,0.55) 0%, rgba(107,163,247,0.22) 100%); + border: 1rpx solid rgba(107,163,247,0.35); + border-bottom: none; +} + +.pedestal-silver { + height: 72rpx; + background: linear-gradient(180deg, rgba(168,180,196,0.45) 0%, rgba(168,180,196,0.18) 100%); + border: 1rpx solid rgba(168,180,196,0.28); + border-bottom: none; +} + +.pedestal-bronze { + height: 56rpx; + background: linear-gradient(180deg, rgba(196,168,130,0.45) 0%, rgba(196,168,130,0.18) 100%); + border: 1rpx solid rgba(196,168,130,0.28); + border-bottom: none; +} + +.list-wrap { padding: 0 24rpx; } + +.list-title-row { + display: flex; + align-items: baseline; + justify-content: space-between; + padding: 8rpx 8rpx 20rpx; +} + +.list-title { + font-size: 30rpx; + font-weight: 700; + color: rgba(255,255,255,0.85); +} + +.list-range { + font-size: 22rpx; + color: rgba(255,255,255,0.3); +} + +.list-card { + position: relative; + margin-bottom: 14rpx; + border-radius: 18rpx; + overflow: hidden; + border: 1rpx solid rgba(255,255,255,0.05); +} + +.list-card-bg { + position: absolute; + top: 0; left: 0; + width: 100%; height: 100%; + z-index: 0; +} + +.list-card-body { + position: relative; + z-index: 1; + display: flex; + align-items: center; + padding: 20rpx 22rpx; + background: rgba(12, 16, 28, 0.92); +} + +.lc-rank { + width: 48rpx; + flex-shrink: 0; + text-align: center; +} + +.lc-rank text { + font-size: 32rpx; + font-weight: 700; + color: rgba(255,255,255,0.18); +} + +.lc-avatar { + width: 80rpx; height: 80rpx; + border-radius: 50%; + flex-shrink: 0; + margin: 0 16rpx 0 6rpx; + border: 2rpx solid rgba(107, 163, 247, 0.2); + background: #1a2030; +} + +.lc-info { flex: 1; min-width: 0; } + +.lc-name { + display: block; + font-size: 28rpx; + font-weight: 600; + color: rgba(255,255,255,0.92); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.lc-uid { + display: block; + margin-top: 4rpx; + font-size: 22rpx; + color: rgba(255,255,255,0.32); +} + +.lc-tags { + display: flex; + flex-wrap: wrap; + gap: 8rpx; + margin-top: 8rpx; +} + +.lc-tag { + font-size: 20rpx; + color: rgba(255,255,255,0.5); + background: rgba(255,255,255,0.1); + padding: 2rpx 10rpx; + border-radius: 6rpx; +} + +.lc-score { + flex-shrink: 0; + text-align: right; + margin-left: 10rpx; +} + +.lc-money { + display: block; + font-size: 28rpx; + font-weight: 700; + color: #8EB8FF; +} + +.lc-label { + display: block; + margin-top: 2rpx; + font-size: 20rpx; + color: rgba(255,255,255,0.32); +} + +.bottom-gap { height: 48rpx; } diff --git a/miniprogram/pages/guanshipaihang/guanshipaihang.js b/miniprogram/pages/guanshipaihang/guanshipaihang.js new file mode 100644 index 0000000..eb7b020 --- /dev/null +++ b/miniprogram/pages/guanshipaihang/guanshipaihang.js @@ -0,0 +1,6 @@ +// 已合并到统一排行榜页,保留路由兼容 +Page({ + onLoad() { + wx.redirectTo({ url: '/pages/dashoupaihang/dashoupaihang?type=guanshi' }) + }, +}) diff --git a/miniprogram/pages/sjpaihang/sjpaihang.js b/miniprogram/pages/sjpaihang/sjpaihang.js new file mode 100644 index 0000000..e6b9440 --- /dev/null +++ b/miniprogram/pages/sjpaihang/sjpaihang.js @@ -0,0 +1,6 @@ +// 已合并到统一排行榜页,保留路由兼容 +Page({ + onLoad() { + wx.redirectTo({ url: '/pages/dashoupaihang/dashoupaihang?type=shangjia' }) + }, +}) diff --git a/miniprogram/utils/avatar.js b/miniprogram/utils/avatar.js new file mode 100644 index 0000000..a53a361 --- /dev/null +++ b/miniprogram/utils/avatar.js @@ -0,0 +1,19 @@ +/** 头像 URL 解析(排行榜等页面共用) */ +export function getDefaultAvatarUrl(app) { + const g = app || getApp(); + const oss = g.globalData.ossImageUrl || ''; + const def = g.globalData.morentouxiang || ''; + if (!def) return ''; + if (def.startsWith('http')) return def; + return oss + def.replace(/^\//, ''); +} + +export function resolveAvatarUrl(path, app) { + if (!path || path === 'null' || path === 'undefined') return ''; + const s = String(path).trim(); + if (!s) return ''; + if (s.startsWith('http')) return s; + const g = app || getApp(); + const oss = g.globalData.ossImageUrl || ''; + return oss + s.replace(/^\//, ''); +}