Files
a_long/miniprogram/pages/dashoupaihang/dashoupaihang.js
2026-06-27 01:26:11 +08:00

268 lines
7.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 统一排行榜(打手/管事/组长/商家)— 对齐星雀 fighter-rank排序按收益/流水
* POST /yonghu/phbhqsj
*/
import request from '../../utils/request.js'
import { resolveAvatarUrl, getDefaultAvatarUrl } from '../../utils/avatar.js'
import { getPaihangImgUrls } from '../../utils/page-assets.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: 'paifa_jine',
sortLabel: '流水',
mainType: 'money',
metrics: [
{ field: 'paifa_dingdan_shu', label: '派单量', type: 'int' },
{ field: 'jiesuan_dingdan_shu', label: '成交量', type: 'int' },
{ field: 'jiesuan_jine', label: '结算额', type: 'money' },
],
},
}
function buildAvatar(path, app) {
const def = getDefaultAvatarUrl(app)
if (!path || path === 'null' || path === 'undefined') 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._onConfigReady = () => this.initPageAssets()
getApp().on('configReady', this._onConfigReady)
this.initPageAssets()
this.applyRole(validRole, false)
this.fetchRankList()
},
onUnload() {
if (this._onConfigReady) {
getApp().off('configReady', this._onConfigReady)
}
},
onPullDownRefresh() {
this.initPageAssets()
this.fetchRankList().finally(() => wx.stopPullDownRefresh())
},
initPageAssets() {
this.syncDefaultAvatar()
this.setData({ imgUrls: getPaihangImgUrls() })
},
syncDefaultAvatar() {
const def = getDefaultAvatarUrl()
if (def && def !== this.data.defaultAvatar) {
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.initPageAssets()
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.initPageAssets()
this.syncDefaultAvatar()
this.ensureAvatars()
this.registerNotificationComponent()
},
})