统一排行榜页:四角色七时段,对接 phbhqsj 新接口
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
345
miniprogram/app.js
Normal file
345
miniprogram/app.js
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
262
miniprogram/pages/dashoupaihang/dashoupaihang.js
Normal file
262
miniprogram/pages/dashoupaihang/dashoupaihang.js
Normal file
@@ -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()
|
||||||
|
},
|
||||||
|
})
|
||||||
11
miniprogram/pages/dashoupaihang/dashoupaihang.json
Normal file
11
miniprogram/pages/dashoupaihang/dashoupaihang.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"usingComponents": {
|
||||||
|
"global-notification": "/components/global-notification/global-notification"
|
||||||
|
},
|
||||||
|
"navigationBarTitleText": "排行榜",
|
||||||
|
"navigationBarBackgroundColor": "#0d1117",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"enablePullDownRefresh": true,
|
||||||
|
"backgroundColor": "#0d1117",
|
||||||
|
"backgroundTextStyle": "light"
|
||||||
|
}
|
||||||
127
miniprogram/pages/dashoupaihang/dashoupaihang.wxml
Normal file
127
miniprogram/pages/dashoupaihang/dashoupaihang.wxml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
<view class="rank-page">
|
||||||
|
<image class="page-bg" src="{{imgUrls.pageBg}}" mode="aspectFill" />
|
||||||
|
|
||||||
|
<view class="top-bar">
|
||||||
|
<view class="top-row">
|
||||||
|
<text class="page-title">{{roleMeta.title}}</text>
|
||||||
|
<view class="refresh-wrap" bindtap="onRefreshTap">
|
||||||
|
<image class="refresh-ico" src="{{imgUrls.refreshIcon}}" mode="aspectFit" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<scroll-view scroll-x class="role-scroll" enhanced show-scrollbar="{{false}}">
|
||||||
|
<view class="role-line">
|
||||||
|
<view
|
||||||
|
wx:for="{{roleList}}" wx:key="key"
|
||||||
|
class="role-chip {{currentRole === item.key ? 'on' : ''}}"
|
||||||
|
data-role="{{item.key}}" bindtap="onRoleTap"
|
||||||
|
>{{item.label}}</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="date-grid">
|
||||||
|
<view
|
||||||
|
wx:for="{{dateList}}" wx:key="key"
|
||||||
|
class="date-chip {{currentDate === item.key ? 'on' : ''}}"
|
||||||
|
data-date="{{item.key}}" bindtap="onDateTap"
|
||||||
|
>{{item.label}}</view>
|
||||||
|
</view>
|
||||||
|
<text class="sort-tip">{{currentDate}} · 按{{sortLabel}} · TOP50</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="state-wrap" wx:if="{{isLoading}}">
|
||||||
|
<view class="loader"></view>
|
||||||
|
<text>加载中</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="state-wrap" wx:elif="{{isEmpty}}">
|
||||||
|
<image class="state-img" src="{{imgUrls.emptyIcon}}" mode="aspectFit" />
|
||||||
|
<text>暂无排行数据</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view wx:else scroll-y class="body-scroll" enhanced show-scrollbar="{{false}}">
|
||||||
|
|
||||||
|
<view class="podium-panel" wx:if="{{topThree.length > 0}}">
|
||||||
|
<view class="podium-cols">
|
||||||
|
<view class="p-col p-second" wx:if="{{topThree[1]}}">
|
||||||
|
<view class="p-badge badge-silver"><text>2</text></view>
|
||||||
|
<view class="p-avatar-wrap wrap-silver">
|
||||||
|
<image class="p-avatar" src="{{topThree[1].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="1" binderror="onAvatarError" />
|
||||||
|
</view>
|
||||||
|
<text class="p-name">{{topThree[1].nicheng}}</text>
|
||||||
|
<text class="p-uid">ID {{topThree[1].uid}}</text>
|
||||||
|
<view class="p-amount">
|
||||||
|
<text class="p-money">{{topThree[1].mainPrefix}}{{topThree[1].mainValue}}</text>
|
||||||
|
<text class="p-label">{{topThree[1].mainLabel}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-metrics">
|
||||||
|
<text class="p-metric" wx:for="{{topThree[1].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-pedestal pedestal-silver"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="p-col p-first" wx:if="{{topThree[0]}}">
|
||||||
|
<view class="p-badge badge-first"><text>1</text></view>
|
||||||
|
<view class="p-avatar-wrap wrap-first">
|
||||||
|
<image class="p-avatar p-avatar-lg" src="{{topThree[0].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="0" binderror="onAvatarError" />
|
||||||
|
</view>
|
||||||
|
<text class="p-name p-name-first">{{topThree[0].nicheng}}</text>
|
||||||
|
<text class="p-uid">ID {{topThree[0].uid}}</text>
|
||||||
|
<view class="p-amount">
|
||||||
|
<text class="p-money p-money-first">{{topThree[0].mainPrefix}}{{topThree[0].mainValue}}</text>
|
||||||
|
<text class="p-label">{{topThree[0].mainLabel}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-metrics">
|
||||||
|
<text class="p-metric" wx:for="{{topThree[0].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-pedestal pedestal-first"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="p-col p-third" wx:if="{{topThree[2]}}">
|
||||||
|
<view class="p-badge badge-bronze"><text>3</text></view>
|
||||||
|
<view class="p-avatar-wrap wrap-bronze">
|
||||||
|
<image class="p-avatar" src="{{topThree[2].avatar || defaultAvatar}}" mode="aspectFill" data-zone="top" data-index="2" binderror="onAvatarError" />
|
||||||
|
</view>
|
||||||
|
<text class="p-name">{{topThree[2].nicheng}}</text>
|
||||||
|
<text class="p-uid">ID {{topThree[2].uid}}</text>
|
||||||
|
<view class="p-amount">
|
||||||
|
<text class="p-money">{{topThree[2].mainPrefix}}{{topThree[2].mainValue}}</text>
|
||||||
|
<text class="p-label">{{topThree[2].mainLabel}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-metrics">
|
||||||
|
<text class="p-metric" wx:for="{{topThree[2].metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="p-pedestal pedestal-bronze"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="list-wrap" wx:if="{{restList.length > 0}}">
|
||||||
|
<view class="list-title-row">
|
||||||
|
<text class="list-title">完整榜单</text>
|
||||||
|
<text class="list-range">第 4 - {{rankList.length}} 名</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="list-card" wx:for="{{restList}}" wx:key="mingci">
|
||||||
|
<image class="list-card-bg" src="{{imgUrls.cardBg}}" mode="aspectFill" />
|
||||||
|
<view class="list-card-body">
|
||||||
|
<view class="lc-rank"><text>{{item.mingci}}</text></view>
|
||||||
|
<image class="lc-avatar" src="{{item.avatar || defaultAvatar}}" mode="aspectFill" data-zone="rest" data-index="{{index}}" binderror="onAvatarError" />
|
||||||
|
<view class="lc-info">
|
||||||
|
<text class="lc-name">{{item.nicheng}}</text>
|
||||||
|
<text class="lc-uid">ID {{item.uid}}</text>
|
||||||
|
<view class="lc-tags">
|
||||||
|
<text class="lc-tag" wx:for="{{item.metrics}}" wx:key="label" wx:for-item="m">{{m.label}} {{m.value}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="lc-score">
|
||||||
|
<text class="lc-money">{{item.mainPrefix}}{{item.mainValue}}</text>
|
||||||
|
<text class="lc-label">{{item.mainLabel}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bottom-gap"></view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<global-notification id="global-notification" />
|
||||||
415
miniprogram/pages/dashoupaihang/dashoupaihang.wxss
Normal file
415
miniprogram/pages/dashoupaihang/dashoupaihang.wxss
Normal file
@@ -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; }
|
||||||
6
miniprogram/pages/guanshipaihang/guanshipaihang.js
Normal file
6
miniprogram/pages/guanshipaihang/guanshipaihang.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// 已合并到统一排行榜页,保留路由兼容
|
||||||
|
Page({
|
||||||
|
onLoad() {
|
||||||
|
wx.redirectTo({ url: '/pages/dashoupaihang/dashoupaihang?type=guanshi' })
|
||||||
|
},
|
||||||
|
})
|
||||||
6
miniprogram/pages/sjpaihang/sjpaihang.js
Normal file
6
miniprogram/pages/sjpaihang/sjpaihang.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// 已合并到统一排行榜页,保留路由兼容
|
||||||
|
Page({
|
||||||
|
onLoad() {
|
||||||
|
wx.redirectTo({ url: '/pages/dashoupaihang/dashoupaihang?type=shangjia' })
|
||||||
|
},
|
||||||
|
})
|
||||||
19
miniprogram/utils/avatar.js
Normal file
19
miniprogram/utils/avatar.js
Normal file
@@ -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(/^\//, '');
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user